如何跨两个不同的android应用程序共享SharedPreferences文件?
我一直在努力。 基本上,我想要有两个应用程序(它们将始终安装在一起)共享偏好,其中之一就是在后台运行的服务,需要使用偏好(应该拥有偏好,但只有真正需要阅读偏好),另一个应用程序是前端UI应用程序,需要能够写入其他应用程序拥有的首选项文件。 该服务将在后台进行操作(可能由首选项决定),用户界面将允许用户编辑首选项并查看服务中的某些信息。 但是,它们将是不同的软件包/应用程序。
我试着按照这个教程给了我一个关于如何在一个应用程序中可以被另一个应用程序读取的偏好的相当好的想法。 从本质上讲,我通过myContext = createPackageContext("com.example.package",Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
创build一个新的上下文myContext = createPackageContext("com.example.package",Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
然后调用myContext.getSharedPreferences("pref_name", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
但是,我无法从外部应用程序成功地写入首选项 – (SharedPreferences.Editor).commit()返回false,并在logcat中获得有关无法编辑pref_name.xml.bak的警告。
我怎样才能成功地设置我的应用程序,使他们都可以读取和写入相同的首选项文件(存储在其中之一的数据文件夹)?
为文件设置私人模式比较好。 应用程序需要使用相同的一组证书进行签名才能共享此文件。
在两个应用程序中设置sharedUserId是相同的。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.hello" android:versionCode="1" android:versionName="1.0" android:sharedUserId="com.example"> ....
从其他软件包获取上下文:
mContext = context.createPackageContext( "com.example.otherapp", Context.MODE_PRIVATE); mPrefs = mContext.getSharedPreferences("sameFileNameHere", Activity.MODE_PRIVATE);
像往常一样从SharedPreference获取项目。 你现在可以访问它。
首先,我应该注意到,这不是官方的支持,虽然可能有一个支持的方式来做到这一点(即它不会是这种方法)未来添加到Android(来源为这两个索赔:见本链接的第二段) 。
再一次,这是不受支持的,可能很不稳定。 我主要是做这个实验来看看是否有可能; 如果您计划将此方法实际应用到应用程序中,请格外小心。
但是,如果满足一些要求,似乎可以在应用程序之间共享偏好。 首先,如果您希望应用程序B能够访问应用程序A的首选项,则应用程序B的应用程序包名称必须是应用程序A的应用程序包名称(例如,应用程序A: com.example.pkg
应用程序B: com.example.pkg.stuff
)。 此外,他们不能同时访问该文件(我假设适用于在活动之间访问它们的规则相同,如果要确保primefaces访问,则必须使用其他保护措施,如.wait( )和.notify(),但我不会在这里)。
注意:所有这些都可以在2.2和2.3.3上的仿真器上运行 – 我还没有广泛testing过各种设备或Android版本。
在应用程序中要做的事情(上面的应用程序A):
1.)声明SharedPreferences文件
这很简单。 只需在您的类中为您的sharedpreferences文件和编辑器声明一对variables,然后在onCreate方法中实例化它们即可。 您现在可以在首选项中放入一个string,以确保其他应用可以正确读取它。
public class stuff extends Activity { SharedPreferences mPrefs = null; SharedPreferences.Editor mEd= null; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); mPrefs = (getApplicationContext()).getSharedPreferences("svcprefs", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE); mEd = mPrefs.edit(); mEd.putString("test", "original send from prefs owner"); mEd.commit();
2.)设置备份文件 getSharedPreferences方法似乎检查.bak文件以从中加载首选项。 这就是为什么它在文档中说,它不会跨多个进程工作; 为了最大限度地减lessI / O,当你抓取它们的时候,它会加载这些前缀,并且只有在closures应用程序/活动时才备份它们。 但是,如果您从外部应用程序调用此应用程序,则会收到有关文件夹(这是第一个应用程序的数据文件夹)没有正确文件权限的警告。 为了解决这个问题,我们将自己创build.bak文件并使其公开可读/可写。 我select这样做的方法是在我的整个class级中定义三个variables。
final String[] copyToBackup = { "dd", "if=/data/data/com.example.pkg/shared_prefs/prefs.xml", "of=/data/data/com.example.pkg/shared_prefs/prefs.xml.bak", "bs=1024" }; final String[] mainFixPerm = {"chmod", "666", "/data/data/com.example.pkg/shared_prefs/prefs.xml"}; final String[] bakFixPerm = {"chmod", "666", "/data/data/com.example.pkg/shared_prefs/prefs.xml.bak"};
并在我的主类中作出一个函数,将这些作为参数并执行它们
public void execCommand(String[] arg0){ try { final Process pr = Runtime.getRuntime().exec(arg0); final int retval = pr.waitFor(); if ( retval != 0 ) { System.err.println("Error:" + retval); } } catch (Exception e) {} }
这不是非常漂亮或好,但它的工作原理。 现在,在你的onCreate方法(在editor.commit()之后),你将使用三个string中的每一个来调用这个函数。
execCommand(copyToBackup); execCommand(mainFixPerm); execCommand(bakFixPerm);
这将复制文件,并使外部程序可访问主.xml和.xml.bak文件。 你也应该在你的onDestroy()中调用这三个方法来确保数据库在你的应用程序退出时被正确地备份,并且在你调用应用程序中其他地方的getSharedPreferences之前调用它们(否则它会加载.bak文件如果另一个进程正在编辑主要的.xml文件,则可能会过时)。 虽然这就是你在这个应用程序中所需要做的。 您可以在此活动的其他地方调用getSharedPreferences,它将从.xml文件中获取所有数据,然后调用getdatatype(“key”)方法并检索它。
访问文件中要做的事(上面的应用程序B)
1.)写入文件
这更简单。 我在这个活动上做了一个button,并在它的onClick方法中设置了代码,这会将一些东西保存到共享的首选项文件中。 请记住,应用程序B的包必须是应用程序A的包的孩子。 我们将根据App A的上下文创build一个上下文,然后在该上下文中调用getSharedPreferences。
prefsbutton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Context myContext = null; try { // App A's context myContext = createPackageContext("com.example.pkg", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE); } catch (NameNotFoundException e) {e.printStackTrace();} testPrefs = myContext.getSharedPreferences("svcprefs", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE); testEd = testPrefs.edit(); String valueFromPrefs = testPrefs.getString("test", "read failure"); TextView test1 = (TextView)findViewById(R.id.tvprefs); test1.setText(valueFromPrefs); testEd.putString("test2", "testback"); boolean edit_success = testEd.commit();
这抓住了我在另一个应用程序中设置的string,并在此应用程序的文本视图中显示它(或错误消息)。 另外,它在首选项文件中设置一个新的string并提交更改。 运行之后,如果其他应用程序调用getSharedPreferences,它将检索包含此应用程序更改的文件。