Communication Utils
Introduction
The Migration SDK provides a utility module for facilitating communication between M App and L App.
It's available in migration-client
, migration-host
SDK v0.9.3 or above.
Through this module, M App and L App will register each other as endpoints of the communication and the data will be passed back and forth in a secure way using a custom permission - protectionLevel="signature"
The module provides three kinds of communication methods tailored to its use case.
when a shared data storage is needed : DataStorage
when a one-way event posting is needed : EventHandler
when a complete server-client architecture is needed : RequestHandler
Choose an item below for more detailed guide.
DataStorage
DataStorage is useful when a shared data storage between L App and M App is needed.
Data is stored in a key-value structure.
Use case
The migration SDK uses DataStorage to determine whether the lock screen of the L app is active. The L app updates the value in the DataStorage whenever the lock screen is activated or deactivated, and the M app reads the value from the DataStorage when it wants to check the status of the L app.
How to use it
Access a DataStorage instance through MigrationXXX.getDataStorage()
1. Saving data
boolean put(String key, String value)
: Stores value mapped to key.Return
true
if successfully stored, orfalse
if failed.
For one key, put must be called on one side only. Each app stores its data in its store when it calls put. It searches its store by calling get, and then searches the store of the other app if there is no value in its own store. If you put different values for puts in both apps for the same key, they will be stored in their own repositories, so the values will not be shared.
2. Data retrieval
String get(String key)
: Synchronously retrieves the value mapped to the key and returns it.void getAsync(String key, DataStorage.AsyncQueryListener listener)
: Asynchronously retrieves the value mapped to key and passes it toAsyncQueryListener
.Parameters
AsyncQueryListener
void onQueryComplete(String value)
: Invoked when the search is complete andvalue
is passed as a parameter (null
if none).
MigrationXXX.getDataStorage().put("SHARED_CONFIG_KEY", "config_value");
// Synchronous
String value = MigrationXXX.getDataStorage().get("SHARED_CONFIG_KEY");
// Asynchronous
MigrationXXX.getDataStorage().getAsync("SHARED_CONFIG_KEY", new DataStorage.AsyncQueryListener() {
@Override
public void onQueryComplete(String value) {
}
});
EventHandler
This is used when the event is forwarded from the Sender to the Receiver only in one direction.
The Sender and Receiver roles are not fixed for a specific app but depend on how it is used.
Since the name of each event is the key, both the Sender and the Receiver must use the same event name for one event.
Bundle is used to add additional information when delivering events.
How to use
Access an EventHandler instance through MigrationXXX.getEventHandler()
.
1. Sending events
void post(String eventName)
: Send an event to a Receiver.void post(String eventName, Bundle extras)
: Sends an event to the Receiver with additional data in the form of a bundle.
2. Receiving events
void registerEventListener(String eventName, EventHandler.OnEventListener listener)
: The logic for receiving a specific event is implemented inOnEventListener
and registered by mapping it toeventName
.Parameters
OnEventListener
void onEvent(Bundle extras)
: Invoked when an event is received, and additional data sent by the Sender is passed as a parameter (if additional data does not exist, an empty Bundle is passed instead of anull
object).
// Sender
Bundle eventData = new Bundle();
eventData.putString("extra_info", "extra_value");
MigrationXXX.getEventHandler().post("SAMPLE_EVENT", eventData);
// Receiver
MigrationXXX.getEventHandler().registerEventListener("SAMPLE_EVENT", new EventHandler.OnEventListener() {
@Override
public void onEvent(Bundle extras) {
Log.d(TAG, "onReceive SAMPLE_EVENT");
String extraInfo = extras.getString("extra_info"); // "extra_value" returned
...
}
});
RequestHandler
Use when you need to organically process requests and responses between two apps, like a server-client structure.
The Server and Client roles are not fixed for a specific app but depend on how it is used.
Because each request-response pair is distinguished by a request code, both the server and the client must use the same request code.
Bundle is used for data exchanged between request and response.
How to use
Get a RequestHandler instance through MigrationXXX.getRequestHandler()
.
1. Server
void registerResponder(int requestCode, MsgRequestHandler.Responder responder)
: Implement a response when a request comes from a client.Parameters
requestCode
: Unique code to distinguish requestsResponder
Bundle respond(Bundle parameters)
: Called when a request comes from the client, and the parameters passed in are the additional parameters contained in the request. You must return the response in the Bundle.
2. Client
void request(int requestCode, Bundle params, Request.OnResponseListener listener)
: It sends a request to the server and implements a callback that handles the response.Parameters
requestCode
: Unique code to distinguish requestsparams
: If you need to pass parameters along with requests, pass it in bundle form.OnResponseListener
void onResponse(Bundle response)
: Invoked when communication with the server app is successful, and the server's response data is passed as a parameter (if response data does not exist, an empty Bundle is passed instead of anull
object).void onFail(Request.FailReason failReason)
: Invoked when communication with the server app fails. The cause of the failure is passed as a parameter.
// Server
MigrationXXX.getRequestHandler().registerResponder(1000, new MsgRequestHandler.Responder() {
@Override
public Bundle respond(Bundle parameters) {
Bundle response = new Bundle();
response.putString("response_key", "response_sample");
return response;
}
});
// Client
MigrationXXX.getRequestHandler().request(1000, null, new Request.OnResponseListener() {
@Override
public void onResponse(Bundle response) {
String value = response.getString("response_key"); // "response_sample" returned
...
}
@Override
public void onFail(Request.FailReason failReason) {
}
});