2019独角兽企业重金招聘Python工程师标准>>>

shareUserId介绍:

Android给每个APK进程分配一个单独的空间,manifest中的userid就是对应一个分配的Linux用户ID,并且为它创建一个沙箱,以防止影响其他应用程序(或者其他应用程序影响它)。用户ID 在应用程序安装到设备中时被分配,并且在这个设备中保持它的永久性。

通常,不同的APK会具有不同的userId,因此运行时属于不同的进程中,而不同进程中的资源是不共享的,在保障了程序运行的稳定。然后在有些时候,我们自己开发了多个APK并且需要他们之间互相共享资源,那么就需要通过设置shareUserId来实现这一目的。

通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是可以互相访问任意数据. 也可以配置成运行成不同的进程, 同时可以访问其他APK的数据目录下的数据库和文件.就像访问本程序的数据一样。

shareUserId设置:

在需要共享资源的项目的每个AndroidMainfest.xml中添加shareuserId的标签。

android:sharedUserId="com.example"

id名自由设置,但必须保证每个项目都使用了相同的sharedUserId。一个mainfest只能有一个Shareuserid标签。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.shareusertesta"android:versionCode="1"android:versionName="1.0" android:sharedUserId="com.example">

\data\data\自定义的package\ 路径下的互相访问

每个安装的程序都会根据自己的包名在手机文件系统的data\data\your package\建立一个文件夹(需要su权限才能看见),用于存储程序相关的数据。

在代码中,我们通过context操作一些IO资源时,相关文件都在此路径的相应文件夹中。比如默认不设置外部路径的文件、DB等等。

正常情况下,不同的apk无法互相访问对应的app文件夹。但通过设置相同的shareUserId后,就可以互相访问了。代码如下。

apk A:

//程序A:
public class MainActivityA extends Activity {TextView textView;@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = (TextView)findViewById(R.id.textView1);WriteSettings(this, "123");}    public void WriteSettings(Context context, String data) {FileOutputStream fOut = null;OutputStreamWriter osw = null;        try {            //默认建立在data/data/xxx/file/ fOut = openFileOutput("settings.dat", MODE_PRIVATE);            osw = new OutputStreamWriter(fOut);osw.write(data);osw.flush();Toast.makeText(context, "Settings saved", Toast.LENGTH_SHORT).show();} catch (Exception e) {e.printStackTrace();Toast.makeText(context, "Settings not saved", Toast.LENGTH_SHORT).show();} finally {            try {osw.close();fOut.close();} catch (IOException e) {e.printStackTrace();}}}

apk B:

/程序B:
public class MainActivityB extends Activity {TextView textView;@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = (TextView) this.findViewById(R.id.textView1);        try {            //获取程序A的contextContext ctx = this.createPackageContext(                    "com.example.shareusertesta",             Context.CONTEXT_IGNORE_SECURITY);String msg = ReadSettings(ctxDealFile);Toast.makeText(this, "DealFile2 Settings read" + msg,Toast.LENGTH_SHORT).show();WriteSettings(ctx, "deal file2 write");} catch (NameNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();}}    public String ReadSettings(Context context) {FileInputStream fIn = null;InputStreamReader isr = null;        char[] inputBuffer = new char[255];String data = null;        try {            //此处调用并没有区别,但context此时是从程序A里面获取的fIn = context.openFileInput("settings.dat");isr = new InputStreamReader(fIn);isr.read(inputBuffer);data = new String(inputBuffer);textView.setText(data);Toast.makeText(context, "Settings read", Toast.LENGTH_SHORT).show();} catch (Exception e) {e.printStackTrace();Toast.makeText(context, "Settings not read", Toast.LENGTH_SHORT).show();} finally {            try {isr.close();fIn.close();} catch (IOException e) {e.printStackTrace();}}        return data;}    public void WriteSettings(Context context, String data) {FileOutputStream fOut = null;OutputStreamWriter osw = null;        try {//此处调用并没有区别,但context此时是从程序A里面获取的fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);            osw = new OutputStreamWriter(fOut);osw.write(data);osw.flush();Toast.makeText(context, "Settings saved", Toast.LENGTH_SHORT).show();} catch (Exception e) {e.printStackTrace();Toast.makeText(context, "Settings not saved", Toast.LENGTH_SHORT).show();} finally {            try {osw.close();fOut.close();} catch (IOException e) {e.printStackTrace();}}}
}

如果A和B的mainfest中设置了相同的shareuserId,那么B的read函数就能正确读取A写入的内容。否则,B无法获取该文件IO。

通过这种方式,两个程序之间不需要代码层级的引用。之间的约束是,B需要知道A的file下面存在“settings.dat”这个文件以及B需要知道A的package的name。

Resources和SharedPreferences的共享

通过shareuserId共享,我们可获取到程序A的context。因此,我们就可以通过context来获取程序A对应的各种资源。比较常用的就是Raw资源的获取,如一些软件的apk皮肤包就是采用了这种技术,将主程序和皮肤资源包分在两个apk中。

获取Resources很简单,在程序A和B的mainfest中设置好相同的shareuserId后,通过createPackageContext获取context即可。之后就和原来的方式一样,通过getResources函数获取各种资源,只是此时的context环境是目标APP的context环境。

//B中调用
Context friendContext = this.createPackageContext( "com.example.shareusertesta",Context.CONTEXT_IGNORE_SECURITY);//在B中获取A的各种资源
friendContext.getResources().getString(id);
friendContext.getResources().getDrawable(id);

可看见,与一般获取资源的方式并没有区别,只是获取context时有所不同。很简单的就能想到我们会在项目中对资源操作、IO操作等分装一个工具类,通过传递context来区分目标,这样能很好的简化复杂性。

分析这段代码,可看见程序A和B之间的联系有三个:

1 mainfest中声明shareuserId时需要知道一个共同的userId

2 createpackageContext时需要知道目标APK的package的name

3 获取资源时需要知道该资源的对应ID

资源的R.id的讨论

在上面的三个联系中,1和2并不复杂,但是“3 获取资源时需要知道该资源的对应ID”,这一点是一种比较麻烦的约束,会造成一些复杂的情况。

比如,在程序A中我们添加了一个String资源share_test_a ,现在需要在B中获取该资源。于是我们就通过context.getResources().getString(id)来获取。

注意,share_test_a是在A中定义的,在A里面我们可以简单的通过“R.string.share_test_a”来标示id。但是在程序B中,我们并未在strings.xml中定义过“share_test_a”这个string,因此不存在“R.string.share_test_a”这个标示ID,也就是说连编译都不通过,。

那么,我们该怎么来获取ID呢?一般会想到两种方法,一是利用外部存储文件保存A中的这个id,然后在B中读取id后再获取资源;二是在B中同样定义一个”share_test_a”的变量。两种方案是否可行,我们在下面讨论。

SharedPreferences传递R.id

先来看下方案一,最简单的能想到的方式就是File、DB和SharedPreferences。三者原理相同择一即可。以SharedPreferences举例。

/程序A中SharedPreferences sp = this.getSharedPreferences("sp", MODE_PRIVATE);
Editor editor = sp.edit();
editor.putInt("Rkey", R.string.share_test_a);
editor.commit();
//程序B中Context friendContext = this.createPackageContext("com.example.shareusertesta",Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sp = friendContext.getSharedPreferences("sp", MODE_PRIVATE);int Rkey = sp.getInt("Rkey", 0);
String ts = friendContext.getResources().getString(Rkey);

从上面代码看到,我们通过SharedPreferences间接的中转了R的id。两者的约束是对存储的内容需要一个key来命名并在两个app中统一,以及需要知道该key对应的类型(int、string等)。

这种方式可以准确的获取资源,不需要A和B之间有代码级别的引用。但需要添加一层map来协调key的含义

设置相同的资源名

不可行。

访问安全性

上文中通过测试,验证了同key下设置相同shareuserid后可共享资源,否则失败。

但还有两种情况尚未讨论。一是假设A和C用两个不同的签名,但设置相同的shareuserid,那么能否共享资源。二是假设A用签名后的apk安装,C用usb直连调试(即debug key),两者设置相同的shareuserid,那么能否共享资源。

经过测试,不论是USB调试还是新签名APK都安装不上。

再进一步测试后发现,能否安装取决于之前手机中是否已经存在对应该shareduserId的应用。如有,则需要判断签名key是否相同,如不同则无法安装。也就是说,如果你删除a和b的应用先装c,此时c的安装正常,而原来a和b的安装就失败了(a、b同key,c不同key,三者userId相同)。

其他讨论

1 android:sharedUserId="android.uid.system" 如果这么设置,可实现提权的功能,修改系统时间等需要core权限的操作就可完成了。但看到有人说会造成sd卡读取bug,网上有不少解决方案(未测试)。

2 修改shareuserId后,usb开发调试安装没有问题,但是利用Ecplise打包签名APK后,部分机型会造成无法安装的问题。网上有提到需要源码环境mm打包或其他,较麻烦暂未验证。

目前测试了三台机子:三星S3自带系统失败;华为一机子成功;三星一刷官方anroid系统的机子成功。初步估计部分厂商修改了一定的内核,造成安装失败,具体兼容性情况有待进一步测试

3 使用shareuserid后,对同系列的产品的签名key必须统一,不要丢失。否则后面开发的系列app就无法获取数据了。此外,注意从没有userId的版本到有userId版本时的升级,也可能存在一定的安全权限问题。

转载于:https://my.oschina.net/u/255456/blog/662364

sharedUserId相关推荐

  1. android:sharedUserId作用

    前言 Android给每个APK进程分配一个单独的空间,manifest中的userid就是对应一个分配的Linux用户ID,并且为它创建一个沙箱,以防止影响其他应用程序(或者被其他应用程序影响). ...

  2. android:shareduserid获取资源,关于 android:sharedUserId=android.uid.system

    先在配置文件AndroidManifest.xml中的manifest里设置,例如: package="com.Demo" android:versionCode="10 ...

  3. android sharedUserId 共享用户

    android:sharedUserId="com.aaa" 相同sharedUserId的app必须使用同一个证书, 被分配同一个uid app安装->sharedUser ...

  4. Android之用sharedUserId来实现不同应用(APK)数据共享

    android:sharedUserId 当APK安装的时候,userid这个标志就会产生.APK在设备上的整个生命周期中,这个ID不再改变.不同设备上同一个应用包可能有不同的userid,重要的是在 ...

  5. 设置android:sharedUserId=android.uid.system 支持 sdcard读写

    在AndoridManifest.xml文件中添加android:sharedUserId="android.uid.system" 可以让应用程序获得系统权限,完成很多setti ...

  6. Android如何通过shareduserid获取系统权限

    2019独角兽企业重金招聘Python工程师标准>>> android会为每个apk进程分配一个单独的空间(比如只能访问/data/data/自己包名下面的文件),一般情况下apk之 ...

  7. android:sharedUserId=android.uid.system 的使用

    系统权限使用 android:sharedUserId="android.uid.system" 通过Shared User id,拥有同一个User id的多个APK可以配置成运 ...

  8. Android不同APP间共享数据:sharedUserId

    Android-sharedUserId数据权限 Android给每个APK进程分配一个单独的用户空间,其manifest中的userid就是对应一个Linux用户 (Android 系统是基于Lin ...

  9. android系统sharedUserId: SYSTEM_UID+PHONE_UID+BLUETOOH_UID+LOG_UID+NFC_UID

    android.uid.system (SYSTEM_UID, 1000) android.uid.phone (PHONE_UID, 1001) android.uid.bluetooth (BLU ...

最新文章

  1. XtraGrid GridView设置默认选中的行颜色
  2. pip安装包时如何指定安装在哪个python下?
  3. java form 上传文件_form java springmvc怎么上传文件
  4. Xamarin的坑 - 绑定(一) - 拿微信iOS SDK 简单说起
  5. 显示当前没有家庭组计算机,已创建家庭组且加入家庭组,但显示“当前没有其他可用的家庭组计算机?”...
  6. TeraData数据库,将Excel文件存入数据库并取出打开
  7. 使用IDEA在Maven中创建MyBatis逆向工程以及需要注意的问题(入门)
  8. description----NSData To NSString
  9. git版本回退(回退提交到本地仓库代码)
  10. eclipse maven 打war包的几种方式
  11. web前端网页界面/css 仿微软官网界面
  12. mysql数据库课程设计_MySql数据库课程设计(学生管理系统).doc
  13. 1.2 XML 的基本语法
  14. dtech串口驱动 linux,帝特USB转串口驱动
  15. 简单线性相关案例-求相关系数
  16. 怎么在服务器上接无线路由器,从别人家拉网线再接无线路由器怎么设置?(二)...
  17. 服务器系统详细安装步骤
  18. 类型 List 不是通用的;不能使用参数() 将它参数化
  19. 不要在本该奋斗的年纪选择了安逸
  20. 用cocos实现的《我的世界》已经上线微信小游戏,分享一下主要技术

热门文章

  1. sql server优化策略
  2. 【漏洞复现】WordPress插件Quizlord 2.0 XSS漏洞复现与分析
  3. 深入redis内部--内存管理
  4. JS编程建议——37:推荐使用replace(1)
  5. 初学Python的学习笔记7----偏函数、模块、重点是面向对象
  6. 苹果内购和 Apple Pay
  7. js 的try catch应用
  8. 连接的管道(最小生成树)
  9. Android使用Apache HttpClient发送GET、POST请求
  10. 用C#实现支持gmail邮件发送