If you do not want to solve the problem with ContentProvider
, or if it is possible that both applications can be installed and used, there is another solution.
Code and Usage
Assume that the data in question belongs to the class:
class DataToBeShared() {
Then add the class to both applications as follows:
public class StoredInfoManager { public static String codeAppType = "apptype"; public static String codeTimestamp = "timestamp"; public static String codeData = "data"; public static String codeResponseActionString = "arstring"; public static String responseActionString = "com.me.my.app.DATA_RESPONSE"; private static int APP_UNKNOWN = 0; private static int APP_FREE = 1; private static int APP_PAID = 2; private static String freeSharedPrefName = "com.me.my.app.free.data"; private static String paidSharedPrefName = "com.me.my.app.paid.data";
This is still a fairly standard system for storing shared preferences. Now the fun begins. First, make sure that there is a private method for retrieving the data stored above and a private method for broadcasting it.
private static DataToBeshared getData(Context context) { SharedPreferences settings = context.getSharedPreferences(prefName, Context.MODE_PRIVATE); DataToBeShared result = new DataToBeShared(); // Your code here to fill out result from Shared preferences. // See the developer page for SharedPreferences for details. // And return the result. return result; } private static void broadcastData(Context context, DataToBeShared data, String intentActionName) { Bundle bundle = new Bundle(); bundle.putInt(codeAppType, appType); bundle.putParcelable(codeData, data); Intent intent = new Intext(intentActionString); intent.putEXtras(bundle); context.sendBroadcast(intent); }
Create a BroadcastReceiver
class to catch data responses from another application for our data:
static class CatchData extends BroadcastReceiver { DataToBeShared data = null; Long timestamp = 0L; int versionListeningFor = Version.VERSION_UNKNOWN; Timeout timeout = null;
We will now provide a static access feature for using applications. Note that it does not return anything that was done by the response catcher above.
public static void geDataFromPhone(Context context) { DataToBeStored myData = getData(context); // See security discussion point 2 for this next line String internalResponseActionString = "com.me.my.app.blah.hohum." + UUID.randomUUID(); // Instantiate a receiver to catch the response from the other app int otherAppType = (appType == APP_PAID ? APP_FREE : APP_PAID); CatchData catchData = new CatchData(context, mydata, otherAppType); context.registerReceiver(catchData, new IntentFilter(internalResponseActionString)); // Send out a request for the data from the other app. Bundle bundle = new Bundle(); bundle.putInt(codeAppType, otherAppType); bundle.putString(codeResponseActionString, internalResponseActionString); bundle.putString(CatchDataRequest.code_password, CatchDataRequest.getPassword()); Intent intent = new Intent(responseActionString); context.sendBroadcast(intent); }
This is the core. We need another class, as well as a manifest twist. Class (to catch requests from another data application:
public class CatchDataRequest extends BroadcastReceiver { // See security discussion point 1 below public static String code_password = "com.newtsoft.android.groupmessenger.dir.p"; public static String getPassword() { return calcPassword(); } private static String calcPassword() { return "password"; } private static boolean verifyPassword(String p) { if (p == null) return false; if (calcPassword().equals(p)) return true; return false; } @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); if (bundle == null) return; String passwordSent = bundle.getString(code_password); if (!verifyPassword(passwordSent)) return; int versionRequested = bundle.getInt(StoredInfoManager.codeAppType); String actionStringToRespondWith = bundle.getString(StoredInfoManager.codeResponseActionString); // Only respond if we can offer what asked for if (versionRequested != StoredInfoManager.appType) return; // Get the data and respond DataToBrStored data = StoredInfoManager.getData(context); StoredInfoManager.broadcastData(context, data, actionStringToRespondWith); } }
In the manifest, be sure to declare this class as the receiver with the action name matching StoredInfoManager.responseActionString
<receiver android:name="com.me.my.app.CatchDataRequest" android:enabled="true"> <intent-filter> <action android:name="com.me.my.app.DATA_RESPONSE"/> </intent-filter> </receiver>
Using this is relatively simple. The class in which you use the data must extend BroadcastReceiver:
public class MyActivity extends Activity {
Security
The weakness of this method is that anyone can register the receiver to catch the connection between the two applications. The above code goes around this:
Make the broadcast request programmed by using a password. This answer is not suitable for discussing how you can make this password secure, but it is important to understand that you cannot store data when creating a password to verify it later - this is another application that will be checked.
Eliminate the complexity of the response using a unique action code each time.
None of them is proof of a fool. If you just bypass your favorite application colors, you probably don't need any security measures. If you transmit more confidential information, you need both, and you need to think about making the password properly protected.
Other improvements