3. Required permissions
In order to perform network operations in your application, your
manifest must include the following permissions
<uses-permission
android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK
_STATE" />
4. Networking should be
performed over separate thread
To avoid creating an unresponsive UI, don't perform
network operations on the UI thread. By default,
Android 3.0 (API level 11) and higher requires you to
perform network operations on a thread other than
the main UI thread; if you don't, a
NetworkOnMainThreadException is thrown.
5. private String downloadUrl(URL url) throws IOException {
InputStream stream = null;
HttpsURLConnection connection = null;
String result = null;
try {
connection = (HttpsURLConnection) url.openConnection();
connection.setReadTimeout(3000);
connection.setConnectTimeout(3000);
connection.setRequestMethod("GET");
// Already true by default but setting just in case; needs to be true since this request
// is carrying an input (response) body.
connection.setDoInput(true);
// Open communications link (network traffic occurs here).
connection.connect();
publishProgress(DownloadCallback.Progress.CONNECT_SUCCESS);
int responseCode = connection.getResponseCode();
if (responseCode != HttpsURLConnection.HTTP_OK) {
throw new IOException("HTTP error code: " + responseCode);
}
// Retrieve the response body as an InputStream.
stream = connection.getInputStream();
publishProgress(DownloadCallback.Progress.GET_INPUT_STREAM_SUCCESS, 0);
if (stream != null) {
// Converts Stream to String with max length of 500.
result = readStream(stream, 500);
}
} finally {
// Close Stream and disconnect HTTPS connection.
if (stream != null) {
stream.close();
}
if (connection != null) {
connection.disconnect();
}
}
return result;
}
6. Implementation as AsyncTask (more info
at https://developer.android.com/training/
basics/network-ops/connecting.html)
/**
* Implementation of AsyncTask designed to fetch data from
the network.
*/
private class DownloadTask extends AsyncTask<String, Void,
DownloadTask.Result> {
private DownloadCallback<String> mCallback;
DownloadTask(DownloadCallback<String> callback) {
setCallback(callback);
}
void setCallback(DownloadCallback<String> callback) {
mCallback = callback;
}
•
7. /**
* Wrapper class that serves as a union of a
result value and an exception. When the download
* task has completed, either the result value
or exception can be a non-null value.
* This allows you to pass exceptions to the UI
thread that were thrown during doInBackground().
*/
static class Result {
public String mResultValue;
public Exception mException;
public Result(String resultValue) {
mResultValue = resultValue;
}
public Result(Exception exception) {
mException = exception;
}
}
•
8. /**
* Cancel background network operation if we do not have
network connectivity.
*/
@Override
protected void onPreExecute() {
if (mCallback != null) {
NetworkInfo networkInfo =
mCallback.getActiveNetworkInfo();
if (networkInfo == null ||
!networkInfo.isConnected() ||
(networkInfo.getType() != ConnectivityManager.TYPE_WIFI &&
networkInfo.getType() != ConnectivityManager.TYPE_MOBILE)) {
// If no connectivity, cancel task and update
Callback with null data.
mCallback.updateFromDownload(null);
cancel(true);
}
}
}
9. /**
* Defines work to perform on the background thread.
*/
@Override
protected DownloadTask.Result doInBackground(String... urls) {
Result result = null;
if (!isCancelled() && urls != null && urls.length > 0) {
String urlString = urls[0];
try {
URL url = new URL(urlString);
String resultString = downloadUrl(url);
if (resultString != null) {
result = new Result(resultString);
} else {
throw new IOException("No response received.");
}
} catch(Exception e) {
result = new Result(e);
}
}
return result;
}
10. /**
* Updates the DownloadCallback with the result.
*/
@Override
protected void onPostExecute(Result result) {
if (result != null && mCallback != null) {
if (result.mException != null) {
mCallback.updateFromDownload
(result.mException.getMessage());
} else if (result.mResultValue != null) {
mCallback.updateFromDownload
(result.mResultValue);
}
mCallback.finishDownloading();
}
}
11. Another example of AsyncTask usage
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
Usage:
new DownloadFilesTask().execute(url1, url2, url3);
12. Best security practices
• Minimize the amount of sensitive or personal user data that
you transmit over the network.
• Send all network traffic from your app over SSL.
• Consider creating a network security configuration, which
allows your app to trust custom CAs or restrict the set of
system CAs that it trusts for secure communication.
In cryptography, a certificate authority or certification authority
(CA) is an entity that issues digital certificates.
13. Networking Security configuration
The key capabilities of this feature are as follows:
• Custom trust anchors: Customize which Certificate Authorities
(CA) are trusted for an app's secure connections. For example,
trusting particular self-signed certificates or restricting the set of
public CAs that the app trusts.
• Debug-only overrides: Safely debug secure connections in an
app without added risk to the installed base.
• Cleartext traffic opt-out: Protect apps from accidental usage of
cleartext traffic.
• Certificate pinning: Restrict an app's secure connection to
particular certificates.
15. Configuring a Custom CA
res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</
domain>
<trust-anchors>
<certificates src="@raw/my_ca"/>
</trust-anchors>
</domain-config>
</network-security-config>
Add the self-signed or non-public CA certificate, in PEM or DER format, to
res/raw/my_ca.
You can also provide multiple <certificates> elements instead of one.
16. Configuring CAs for Debugging
When debugging an app that connects over HTTPS, you may
want to connect to a local development server, which does not
have the SSL certificate for your production server. In order to
support this without any modification to your app's code, you can
specify debug-only CAs, which are trusted only when
android:debuggable is true, by using debug-overrides.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="@raw/debug_cas"/>
</trust-anchors>
</debug-overrides>
</network-security-config>
17. Opting Out of Cleartext Traffic
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">secure.example.com</domain>
</domain-config>
</network-security-config>
21. Use broadcast receivers carefully
Setting up a BroadcastReceiver that gets called unnecessarily
can be a drain on system resources. The sample application
registers the BroadcastReceiver NetworkReceiver in
onCreate(), and it unregisters it in onDestroy(). This is
more lightweight than declaring a <receiver> in the manifest.
When you declare a <receiver> in the manifest, it can wake
up your app at any time, even if you haven't run it for weeks. By
registering and unregistering NetworkReceiver within the
main activity, you ensure that the app won't be woken up after
the user leaves the app. If you do declare a <receiver> in the
manifest and you know exactly where you need it, you can use
setComponentEnabledSetting() to enable and disable it as
appropriate.
22. Use Firebase Cloud Messaging as an
Alternative to Polling
Every time your app polls your server to check if an update is
required, you activate the wireless radio, drawing power
unnecessarily, for up to 20 seconds on a typical 3G connection.
Firebase Cloud Messaging (FCM) is a lightweight mechanism used
to transmit data from a server to a particular app instance. Using
FCM, your server can notify your app running on a particular device
that there is new data available for it.
Compared to polling, where your app must regularly ping the server
to query for new data, this event-driven model allows your app to
create a new connection only when it knows there is data to
download. The model minimizes unnecessary connections and
reduces latency when updating information within your app.
23. Using Firebase for Networking
Add Firebase to Your Android Project
Prerequisites
• A device running Android 4.0 (Ice Cream Sandwich) or newer,
and Google Play services 10.2.1 or higher
• The Google Play services SDK from the Google Repository,
available in the Android SDK Manager
• The latest version of Android Studio, version 1.5 or higher
24. Use the Firebase Assistant
If you're using the latest version of Android Studio (version 2.2 or
later), we recommend using the Firebase Assistant to connect
your app to Firebase. The Firebase Assistant can connect your
existing project or create a new one for you and automatically
install any necessary gradle dependencies.
To open the Firebase Assistant in Android Studio:
• Click Tools > Firebase to open the Assistant window.
• Click to expand one of the listed features (for example,
Analytics), then click the provided tutorial link (for example,
Log an Analytics event).
• Click the Connect to Firebase button to connect to Firebase
and add the necessary code to your app.
25. Available libs
Gradle Dependency Line Service
com.google.firebase:firebase-core:10.2.1 Analytics
com.google.firebase:firebase-database:10.2.1 Realtime Database
com.google.firebase:firebase-storage:10.2.1 Storage
com.google.firebase:firebase-crash:10.2.1 Crash Reporting
com.google.firebase:firebase-auth:10.2.1 Authentication
com.google.firebase:firebase-messaging:10.2.1 Cloud Messaging and Notifications
com.google.firebase:firebase-config:10.2.1 Remote Config
com.google.firebase:firebase-invites:10.2.1 Invites and Dynamic Links
com.google.firebase:firebase-ads:10.2.1 AdMob
com.google.firebase:firebase-appindexing:10.2.1 App Indexing
26. Firebase authentification for Android
Declare the FirebaseAuth and AuthStateListener objects.
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
27. In the onCreate() method, initialize the FirebaseAuth instance and the
AuthStateListener method so you can track whenever the user signs in or
out.
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// ...
}
};
28. Attach the listener to your FirebaseAuth instance in the onStart()
method and remove it on onStop().
@Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
29. Sign up new users
Create a new createAccount method which takes in an email address and
password, validates them and then creates a new user with the
createUserWithEmailAndPassword method.
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "createUserWithEmail:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Toast.makeText(EmailPasswordActivity.this, R.string.auth_failed,
Toast.LENGTH_SHORT).show();
}
// ...
}
});
EmailPasswordActivity.java
30. Sign in existing users
Create a new signIn method which takes in an email address and password, validates
them, and then signs a user in with the signInWithEmailAndPassword method.
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithEmail:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithEmail:failed", task.getException());
Toast.makeText(EmailPasswordActivity.this, R.string.auth_failed,
Toast.LENGTH_SHORT).show();
}
// ...
}
});
31. Access user information
If a user has signed in successfully you can get their account data at any
point with the getCurrentUser method.
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// Name, email address, and profile photo Url
String name = user.getDisplayName();
String email = user.getEmail();
Uri photoUrl = user.getPhotoUrl();
// Check if user's email is verified
boolean emailVerified = user.isEmailVerified();
// The user's ID, unique to the Firebase project. Do NOT use this value to
// authenticate with your backend server, if you have one. Use
// FirebaseUser.getToken() instead.
String uid = user.getUid();
}