【Android实测】SharePreference的全局只读方式初探

最近的需求要求我的APP开放一些属性数据给其他APP访问,但不能允许其他APP修改我的数据。
在选择实现方式时,对比了content provider和sharepreference,其中,content provider的数据以数据表的形式存在,可允许外部应用进行增删改查,而sharepreference的数据以xml键值对的形式存在,可使用不同的MODE对外部应用的读写权限进行控制,写法简单。因此,最后选择使用sharepreference实现这个功能。

开始测试前,附上sharepreference的几种MODE:

  • MODE_PRIVATE 指定该sharepreferences数据只能被本应用程序读写
  • MODE_WORLD_READABLE 指定该sharepreference数据对其他应用程序可读但不可写
  • MODE_WORLD_WRITEABLE 指定该sharepreference数据对其他应用程序可读可写

首先测试这个功能需要两个APP,一个负责写,另一个负责读,我的开发环境是Android studio,简单的建两个module即可。

APP1有四个按钮,下面这段代码是OnClickListener的内容:

switch (v.getId()) {
    case R.id.save:
        Log.i(TAG, "click btn save");
        SharedPreferences sharedPreferences = getSharedPreferences(SP_NAME, MODE_WORLD_READABLE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString("key1", "value1");
        editor.putString("key2", "value2");
        editor.commit();
        Log.i(TAG, "save sp, over");
        break;
    case R.id.read:
        Log.i(TAG, "click btn read");
        Log.i(TAG, "read sp, mode world readable");
        sharedPreferences = getSharedPreferences(SP_NAME, MODE_WORLD_READABLE);
        Log.i(TAG, "key1 " + sharedPreferences.getString("key1", "no-key1"));
        Log.i(TAG, "key2 " + sharedPreferences.getString("key2", "no-key2"));
        Log.i(TAG, "key3 " + sharedPreferences.getString("key3", "no-key3"));
        Log.i(TAG, "read sp, over");
        break;
    case R.id.clear1:
        Log.i(TAG, "click btn clear1");
        sharedPreferences = getSharedPreferences(SP_NAME, MODE_WORLD_READABLE);
        editor = sharedPreferences.edit();
        editor.remove("key1");
        editor.putString("key2", "");
        editor.commit();
        Log.i(TAG, "clear 1 over");
        break;
    case R.id.clear2:
        Log.i(TAG, "click btn clear1");
        sharedPreferences = getSharedPreferences(SP_NAME, MODE_WORLD_READABLE);
        editor = sharedPreferences.edit();
        editor.clear();
        editor.commit();
        Log.i(TAG, "clear 2 over");
        break;
    default:
        break;
}

APP2有一个按钮,只做读取APP1给出内容的操作,OnClickListener内容如下:

Context context = null;
switch (v.getId()) {
    case R.id.read:
        try {
            context = createPackageContext("com.point.sharepreferencessource", Context.CONTEXT_IGNORE_SECURITY);//com.point.sharepreferencessource是APP1的包名
            Log.i(TAG,"sp context create over");
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if (context != null) {
            SharedPreferences sharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_WORLD_READABLE);
            Log.i(TAG, "read sp, mode world readable");
            Log.i(TAG, "key1 " + sharedPreferences.getString("key1", "no-key1"));
            Log.i(TAG, "key2 " + sharedPreferences.getString("key2", "no-key2"));
            Log.i(TAG, "key3 " + sharedPreferences.getString("key3", "no-key3"));
            Log.i(TAG, "read sp, over");
        }
        break;
    default:
        break;
}

这种方式不需要在manifest中添加任何权限

代码中变量SP_NAME在APP1和APP2中必须相同。TAG可自定义,方便logcat过滤。

APP2中访问APP1的数据,需要知道APP1中存储sharepreference的文件名、key值。实际应用中需要给外部APP提供的接口文档应当写出这些内容。

sharepreference删除单个数据使用edit.remove(key);的方法,删除全部数据可以使用edit.clear();,而使用edit.putString(key,"");会将这个key的value设置为空串,而不是删除。

在APP2中读取的时候发现,下一次读取需要彻底退出APP2,才能正确的读出APP1最新的数据,但APP1可以常驻后台不杀。这里确认每次点击事件中try-catch代码片都重新执行了,但不退出而是放在后台的话,读出的数据是过时的,原因未知。实际对我的需求影响不大,没有继续查。有大神了解原因的请评论,万分感谢。

另外,需要注意的一点是,sharepreference一个文件只能指定一个MODE,如果同时对一个文件进行过private访问和world readable访问,那么这个文件将被private。测试中在APP1里对同一个sharepreference文件名get过这两种之后,在APP2里将会读取不到这个sharepreference文件里的数据,报错为Attempt to read preferences file /data/data/com.***.xml without permission,试图访问一个没有读取权限的文件。

好像写完了。

顺便发现了switch case的一个东西。
在APP1中那段switch case代码中,只有第一个case里面声明了SharePreference sharePreference = ***,在第二个case里面不能再声明,而要直接使用sharePreference = ***这个变量,认为switch在进行条件的比对时会把到匹配的case之前的代码片中声明过的变量全部声明一遍。这种写法理论上不规范,但是实际上可行。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值