Edit in GitHubLog an issue

Network Service

Overview

The NetworkService provides shared functionality to make asynchronous network requests and handle their responses.

Usage

The following code snippet details how to make a simple network request and handle the response.

Java

Copied to your clipboard
import com.adobe.marketing.mobile.services.NetworkRequest;
import com.adobe.marketing.mobile.services.ServiceProvider;
final int CONNECTION_TIMEOUT_MS = 5000;
final int READ_TIMEOUT_MS = 5000;
final String URL_TO_CONNECT = "URL_TO_CONNNECT_TO";
final byte[] body = "SampleRequestBody".getBytes(StandardCharsets.UTF_8);
final Map<String, String> headers = new HashMap<>();
headers.put("myCustomHeaderName", "myCustomHeaderValue");
// Create a NetworkRequest
final NetworkRequest networkRequest = new NetworkRequest(URL_TO_CONNECT, HttpMethod.GET, body, headers, CONNECTION_TIMEOUT_MS, READ_TIMEOUT_MS);
// Make the request
ServiceProvider.getInstance().getNetworkService().connectAsync(networkRequest, response -> {
// handle connection response
// close the response
if (response != null) {
response.close();
}
});
Copied to your clipboard
/**
* A sample implementation of Networking to enable overriding the default implementation of network service.
*/
class MyCustomNetworkService implements Networking {
private final ExecutorService executorService = //
/**
* Initiate an asynchronous network request.
*
* @param request {@link NetworkRequest} used for network connection
* @param callback {@link NetworkCallback} that will receive the {@link HttpConnecting} instance asynchronously.
*
*/
@Override
public void connectAsync(final NetworkRequest request, final NetworkCallback callback) {
// Use an executor service for initiating the network request and dispatching the response.
executorService.submit(
() -> {
try {
// 1. If the network is down, for example, if the device is in airplane mode, the callback should be invoked immediately with a null connection. When the null connection is passed to the callback, the SDK will treat it as a recoverable failure and handle it accordingly.
// callback.call(null);
// 2. If the network is available, the SDK should send out the request and invoke the callback with the corresponding connection.
final HttpConnecting connection = doConnection(request);
if (callback != null) {
// If a callback was provided, invoke the callback with the connection
callback.call(connection);
} else {
// If no callback is passed by the client, close the connection.
connection.close();
}
} catch (Exception e) {
// 3. The connectAsync method should never throw exceptions. Catch any exceptions and invoke the callback with an error response.
if (callback != null) {
callback.call(new ErrorResponse());
}
}
});
}
/**
* Utility method to perform the network connection.
* @praram - the `NetworkRequest` whose details should be used for connecting
*
* @return `MyCustomResponse` after making a connection
*/
private MyCustomResponse doConnection(final NetworkRequest request) {
HttpsURLConnection connection = null;
try {
final URL obj = new URL(request.getUrl());
connection = (HttpsURLConnection) obj.openConnection();
// Set the request method
connection.setRequestMethod(request.getMethod().toString());
// Set the read and connect timeouts
connection.setConnectTimeout(request.getConnectTimeout());
connection.setReadTimeout(request.getReadTimeout());
// set the request properties
final Set<Map.Entry<String, String>> entries = request.getHeaders().entrySet();
for (Map.Entry<String, String> entry : entries) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) {
connection.setSSLSocketFactory(TLSSocketFactory.getInstance());
}
final boolean isPostRequest = "POST".equalsIgnoreCase(connection.getRequestMethod());
if (isPostRequest && request.getBody() != null) {
// If the method is POST, set the length before connection
connection.setFixedLengthStreamingMode(request.getBody().length);
}
connection.connect();
// if the command is POST, send the data to the URL.
if (isPostRequest && request.getBody() != null) {
// Consume the payload
final OutputStream os = new BufferedOutputStream(connection.getOutputStream());
os.write(request.getBody());
os.flush();
os.close();
}
} catch (Exception e) {
// handle exceptions
}
// create and return a response object conforming to the `HttpConnecting` interface.
return new MyCustomResponse(connection);
}
}
  1. Override the default implementation of NetworkService provided by ServiceProvider. This step should occur prior to any other interactions with the SDK. While it is possible to register the network override at any point during the application lifecycle, the override will only function for network requests performed after the registration has taken place.
Copied to your clipboard
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// Set the network override prior to making any other calls to the SDK
ServiceProvider.getInstance().setNetworkService(new MyCustomNetworkService());
MobileCore.setApplication(this);
List<Class<? extends Extension>> extensions = Arrays.asList(...);
MobileCore.registerExtensions(extensions, o -> {
// Any other post registration processing
});
}
}

Overriding NetworkService

The default implementation of the NetworkService provided by the SDK can be overriden to use a custom implementation to cater to your app requirements. This section walks through the steps necessary to create a custom network override, and register it with the SDK.

Java

  1. Create a custom implementation of HttpConnecting that represents a response to a network request. Also, create antoher implementation of HttpConnecting that represents the error response. They will be used to handle network completion when overriding the network stack in place of internal network connection implementation.
  • MyCustomResponse
Copied to your clipboard
class MyCustomResponse implements HttpConnecting {
private final HttpsURLConnection connection;
MyCustomResponse(final HttpsURLConnection connection) {
this.connection = connection;
}
@Override
public InputStream getInputStream() {
try {
return connection.getInputStream();
} catch (IOException e) {
// handle exception
}
}
@Override
public InputStream getErrorStream() {
return connection.getErrorStream();
}
@Override
public int getResponseCode() {
try {
return connection.getResponseCode();
} catch (IOException e) {
// handle exception
}
}
@Override
public String getResponseMessage() {
try {
return connection.getResponseMessage();
} catch (IOException e) {
// handle exception
}
}
@Override
public String getResponsePropertyValue(String responsePropertyKey) {
return connection.getHeaderField(responsePropertyKey);
}
@Override
public void close() {
final InputStream inputStream = this.getInputStream();
final InputStream errorStream = this.getErrorStream();
if (inputStream != null) {
try {
inputStream.close();
} catch (final Exception e) {
// handle exceptions
}
}
if (errorStream != null) {
try {
errorStream.close();
} catch (final Exception e) {
// handle exceptions
}
connection.disconnect();
}
}
}
  • ErrorResponse
Copied to your clipboard
class ErrorResponse implements HttpConnecting {
@Override
public InputStream getInputStream() {
return null;
}
@Override
public InputStream getErrorStream() {
return null;
}
@Override
public int getResponseCode() {
return -1;
}
@Override
public String getResponseMessage() {
return "";
}
@Override
public String getResponsePropertyValue(String responsePropertyKey) {
return "";
}
@Override
public void close() { }
}
  1. Create a custom implementation of Networking interface and, implement the connectAsync method. The implementation of connectAsync should handle the connection establishment with the details provided in the NetworkRequest and, notify the caller of a response using the NetworkCallback parameter.
Copied to your clipboard
/**
* A sample implementation of Networking to enable overriding the default implementation of network service.
*/
class MyCustomNetworkService implements Networking {
private final ExecutorService executorService = //
/**
* Initiate an asynchronous network request.
*
* @param request {@link NetworkRequest} used for network connection
* @param callback {@link NetworkCallback} that will receive the {@link HttpConnecting} instance asynchronously.
*
*/
@Override
public void connectAsync(final NetworkRequest request, final NetworkCallback callback) {
// Use an executor service for initiating the network request and dispatching the response.
executorService.submit(
() -> {
try {
// 1. If the network is down, for example, if the device is in airplane mode, the callback should be invoked immediately with a null connection. When the null connection is passed to the callback, the SDK will treat it as a recoverable failure and handle it accordingly.
// callback.call(null);
// 2. If the network is available, the SDK should send out the request and invoke the callback with the corresponding connection.
final HttpConnecting connection = doConnection(request);
if (callback != null) {
// If a callback was provided, invoke the callback with the connection
callback.call(connection);
} else {
// If no callback is passed by the client, close the connection.
connection.close();
}
} catch (Exception e) {
// 3. The connectAsync method should never throw exceptions. Catch any exceptions and invoke the callback with an error response.
if (callback != null) {
callback.call(new ErrorResponse());
}
}
});
}
/**
* Utility method to perform the network connection.
* @praram - the `NetworkRequest` whose details should be used for connecting
*
* @return `MyCustomResponse` after making a connection
*/
private MyCustomResponse doConnection(final NetworkRequest request) {
HttpsURLConnection connection = null;
try {
final URL obj = new URL(request.getUrl());
connection = (HttpsURLConnection) obj.openConnection();
// Set the request method
connection.setRequestMethod(request.getMethod().toString());
// Set the read and connect timeouts
connection.setConnectTimeout(request.getConnectTimeout());
connection.setReadTimeout(request.getReadTimeout());
// set the request properties
final Set<Map.Entry<String, String>> entries = request.getHeaders().entrySet();
for (Map.Entry<String, String> entry : entries) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) {
connection.setSSLSocketFactory(TLSSocketFactory.getInstance());
}
final boolean isPostRequest = "POST".equalsIgnoreCase(connection.getRequestMethod());
if (isPostRequest && request.getBody() != null) {
// If the method is POST, set the length before connection
connection.setFixedLengthStreamingMode(request.getBody().length);
}
connection.connect();
// if the command is POST, send the data to the URL.
if (isPostRequest && request.getBody() != null) {
// Consume the payload
final OutputStream os = new BufferedOutputStream(connection.getOutputStream());
os.write(request.getBody());
os.flush();
os.close();
}
} catch (Exception e) {
// handle exceptions
}
// create and return a response object conforming to the `HttpConnecting` interface.
return new MyCustomResponse(connection);
}
}
  1. Override the default implementation of NetworkService provided by ServiceProvider. This step should occur prior to any other interactions with the SDK. While it is possible to register the network override at any point during the application lifecycle, the override will only function for network requests performed after the registration has taken place.
Copied to your clipboard
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// Set the network override prior to making any other calls to the SDK
ServiceProvider.getInstance().setNetworkService(new MyCustomNetworkService());
MobileCore.setApplication(this);
List<Class<? extends Extension>> extensions = Arrays.asList(...);
MobileCore.registerExtensions(extensions, o -> {
// Any other post registration processing
});
}
}
Was this helpful?
  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2024 Adobe. All rights reserved.