I've nearly finished writing a game for the Android market. I have a full version and a free version with half the levels. I’ve read of a lot of people in similar situation with the following problem but can’t find a satisfactory solution:
My apps are separate but I want them to share data. At least I want the full version to be able to read the free version’s progress data. If a user finishes the free version, then installs the full, it needs to access the progress info because the first stage of the game is identical to the free version and the progress should be shared/mapped.
From what I have read the best way to save game progress is using SharedPreferences, which is what I’m doing and it’s working perfectly.
On searching for ways to share data I read that the best thing to do is to define the same android:sharedUserId in both AndroidManifest.xml files to be the same value and to ensure both apps are signed with the same key:
What is sharedUserId in Android, and how is it used?
multiple apps, sharing same data directory
I’ve done this and checked it’s working by using ApplicationInfo to see both app’s uids, which are the same. However, I was then expecting to be able to read and write to SharedPrefs from both apps (running at different times) and to be reading/writing the same data. But alas no. If this does not make the apps share the same SharedPreferences, then what data are they sharing by specifying the same sharedUserId?
After some more digging some people seem to be saying I need to access the other app’s context first:
http://thedevelopersinfo.com/2009/11/25/getting-sharedpreferences-from-other-application-in-android/
Can't read SharedPreferences fron another application
So if I want App2 to access App1's data, this gives me the following code in App2’s Activity:
Context otherAppsContext = null;
try {
otherAppsContext = createPackageContext("com.example.app1package",0);
} catch (NameNotFoundException e) {
}
SharedPreferences sharedPrefs = otherAppsContext.getSharedPreferences("TestShareData",Context.MODE_PRIVATE);
But when I ask sharedPrefs for data it still just gives me data from the current app (App2 instead of App1).
Inspecting the otherAppsContext variable I’m not sure what it’s giving me. It has an mBasePackageName property which is the package name of App2 (wrong). But it also has an mPackageInfo property which appears to contain data about App1.
I just don’t know if I’m doing things the right way but am missing something or if this isn't the way to go at all. I just want to link my 2 apps in such a way that one can read the other’s SharedPrefs. How do most full versions of apps link to the free one's data?
Any help would be greatly appreciated!
Sure this happens a lot but think I may have solved my own problem.
Both of my apps (full and free versions) are writing to sharedPrefs under the same name:
SharedPreferences settings = getSharedPreferences( PREFS_NAME, 0 );
Where PREFS_NAME is the same for both apps. When I ask for App1's Context from App2 it gives me a Context but it seems it's a Context that can access both Apps' data?
To explain when I get a Context for App1, from App2 and ask for SharedPreferences giving the name PREFS_NAME, I get the SharedPrefs from App2 instead. But I tried changing the SharedPrefs name for App1 and then accessing that from the context in App2 and suddenly it picks up App1's data.
I don't really know what I'm getting back from the createPackageContext call, it seems to be a handle to both sets of data. But I think I can just make my apps use different names for the SharedPrefs and have the full app just search for the free app's data if it needs to.
Related
tl;dr - Find a way to let a test know it can run, only once my game main menu has loaded
I am writing a game in LibGDX, which doesn't use Android code really, and I have a single test class, that I am using to test various visual aspects of my game.
I want to find a way of letting the test know that the game has loaded to the main menu before running tests.
I have tried to share a shared pref over the two apps, but haven't managed due to using SDK 25 and certain modes being deprecated.
Does anyone have any idea? I have thought of using the sdcard to save some sort of file, but every now and then (I'm testing on the emulator) the sdcard doesn't work (that's a whole other issue)
First I would highly recommend testing on real devices, I personally own 20+ test devices and they all cost below $20 each except a few high end models. The experience and feel is worth the money, but most importantly I believe there are things emulator can't do as well as a production model.
In your case, I think you need some sort of cross app communication to start testing?
Have you tried creating your own SQLite database and contentprovider in 1 app, making it public. Then having the 2nd app contentresolver and access data in the 1st app.
Create a bounded service, bound both apps to it, now inter process communication is possibly and very easy, read any of the millions of documentation on this, start here
https://developer.android.com/guide/components/bound-services.html#Messenger
https://codexample.org/questions/57868/data-sharing-between-two-applications.c
I managed to get the dual shared pref stuff working with the below code
Send data from Application 1 (for ex:Application 1 package name is "com.sharedpref1" ).
SharedPreferences prefs = getSharedPreferences("demopref",
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("demostring", strShareValue);
editor.commit();
Receive the data in Application 2( to get data from Shared Preferences in Application 1).
try {
con = createPackageContext("com.sharedpref1", 0);//first app package name is "com.sharedpref1"
SharedPreferences pref = con.getSharedPreferences(
"demopref", Context.MODE_PRIVATE);
String your_data = pref.getString("demostring", "No Value");
}
catch (NameNotFoundException e) {
Log.e("Not data shared", e.toString());
}
In both application manifest files add same shared user id & label,
android:sharedUserId="any string"
android:sharedUserLabel="#string/any_string"
both are same... and shared user label must from string.xml
like this example.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xxxx"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="aaa.bbb.ccc"
android:sharedUserLabel="#string/any_string">
I had a small issue with the sharedUserId not working when I just had a single word, and apparently it needs to follow a packagename style format (the example I found had 3 sections to it, and this worked for me first time, so I didn't investigate anything else)
I´m currently trying to share information between different applications in Android, the goal I´d like to achieve is having the same behavior the KeyChain data share have in iOS but in Android.
I´ve already given a try using SharedPreferences and using "shareUserId" attribute inside Manifest, (by default Android applications behave as sandBoxes and they are not allowed to share data, they also haven´t a common context, so a "fake" one must be built) issues here come by the fact that is mandatory to know every app´s packageName so the data share happens between those apps with the same shareUserID value. I mean, I would like to access this resources without having to ask for the application that stored them.
Context appOne = createPackageContext("com.xxx.zzz.appOne", CONTEXT_INCLUDE_CODE);
mSharedPref = appOne.getSharedPreferences("Test", Context.MODE_PRIVATE);
Other way I tried was using the AccountManager in order to store that information so other applications could reach it. Bad news were that this account will be shared among all applications installed in the system and i will like this behavior to be more restrictive in terms that I would like to be able to choose which apps will have access to this information and those who won´t.
Reference to related post
(Should you use AccountManager for storing Usernames and Passwords for an Android app?)
Is there anyway to achieve this goal? Any help or hint will be appreciated, been stuck in here for a couple of days... If extra information is needed feel free to ask for it. Thanks in advance.
My app can backup and restore all my data, including the shared preference values. However, when I get all my shared preferences, I also get two with the names "drt" and "drt_ts". I've discovered these are from Admob.
Is there any way for me to iterate through the preferences and get ONLY the one ones my own app has created? There doesn't seem to be any concept of owner or creator.
If you want to have your own SharedPreferences, that is separate from the Default one for your app you should consider using SharedPreferences.getSharedPreferences(String name, int mode). The BackupHandler has support for multiple SharedPreferences files.
If you want to have AdMob save their preferences somewhere else then that is a different question, maybe it is possible, check with the documentation for AdMob?
http://developer.android.com/reference/android/content/Context.html#getSharedPreferences%28java.lang.String,%20int%29
I have 5(any number) android applications which will share some data.
Now when 1st/2nd/3rd..(i couldn't know) android application will get installed by user, it will save a string in the memory(internal memory),
When any other application will get installed, it should know that one of the app has already written data and now it should act as user of this data.
To sum up, first app installed will act as provider and others as users...but all the applications can be potential provider and other as users..
Is this feasible?
i tried using file/shared preference/content providers...but in file, you should know file path before using it which is dependent on package name..
In shared preference, we have to create package context..
In content provider, we have to import provider package..
My real motive is, actually in each app, i register the user first time...
now i want , if user install 2nd app from me, it can just use data of first app and do not ask for register..
but the problem is i don't know which app will be installed first by user..
Please help if i can use some other approach??
i found one thread related to this...
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/W-oOa0x9amg
http://android.bigresource.com/Android-How-to-share-data-between-applications-with-no-dependency-HRMMGMIkL.html
This thread pretty much answers my question, in terms of feasibility and options i have for this scenario.
What's the easiest way to pass data(string value) between two android applications with less or even without permissions? Also in my case first application sends data to un-existed application which is installing and it can't listen for intent right now.
Thanks.
Your question is tricky when you can't ensure that both applications are running. In cases like that, you must rely on some form of persistent storage.
If you're concerned with only a small amount of data, Android provides a SharedPreferences class to share preferences between applications. Most notably, you can add a OnSharedPreferenceChangeListener to each application so they can be notified when the other changes the value.
You can find more information on various different forms of persistent storage on the Android website (http://developer.android.com/guide/topics/data/data-storage.html).
So as you are mentioning intent and extras put to it is the way to go.
If you want to let an application receive data even if it's still installing there is no straight-forward way.
One way is as follows:
In the receiver-part of your code, send a received successfully-extra to the sender-application. If the sender-application does not get the received successfully-message after some time, store the data and wait until the application is installed. you may store this data on sd-card and let the other application read that on first use.
you can also do a check if the application is installed with PackageManager.