通过Android manifest中的sharedUserId属性的设置来实现apk之间的资源共享

本文详细介绍了Android系统中UID的概念及其在数据共享方面的作用。解释了如何通过设置相同的UID实现不同应用间的资源共享,并提供了具体的实现步骤和技术细节。

在Android应用的开发中应该都会有两个进程中需要互相访问数据的需求,而在APK在安装到设备里的时候该应用的userid就已经确定了,

一般情况下都不会再改变,每个应用的进程在默认情况下的userid是不一样的,如adb shell下top命令显示的进程信息中的UID,

  PID PR CPU% S  #THR     VSS     RSS PCY UID      Name

 1436  2   0%    S    15 671956K  33284K  bg system   com.android.deskclock
 1459  2   0%    S    13 666772K  29656K  bg u0_a35   com.android.managedprovisioning
 1483  3   0%    S    23 683604K  36020K  bg u0_a42   com.android.mms
 1519  0   0%    S    23 687924K  39484K  bg u0_a36   com.android.email


那么UID(userid)都有什么作用呢?

众所周知,Android是基于Linux内核的操作系统,一般理解为User Identifier,UID在Linux中就是用户的ID,表明是哪个用户运行了这个程序,

主要用于权限的管理。Linux系统中不同的两个普通用户之间如果没有赋予权限是不能互相访问数据的。

而在Android 中又有所不同,因为Android为单用户系统,这时UID 便被赋予了新的使命——数据共享,为了实现数据共享,Android为每个

应用几乎都分配了不同的UID,不像传统的Linux,每个进程的用户相同就为之分配相同的UID,(当然这也就表明了一个问题,android只

能是单用户系统,在设计之初就被他们的工程师给阉割了多用户),使之成了数据共享的工具。


那么在Android中UID既然是用来进行数据共享的工具,那么我们怎么样才能做到数据共享呢?

Android中的数据共享方式有两种:

1)通过ContentProvider,这个方式是通过实现ContentProvider的抽象方法将需要共享的数据暴露出去,这个后续在细研究,如果需要实现

     组定义的ContentProvider,建议可以参考code/Lollipop/packages/providers/下的原生实现。

2)  通过在AndroidManifest中将android:sharedUserId属性,将需要互相访问的apk中的该属性设置成相同的,这样它们的UID就一样了,就可以

     互相访问各自的数据啦,包括数据库和文件等。

     示例:

     a)首先在AndroidManifest.xml中设置相同的sharedUserId(后面简称为UID),可以看到该id的命名可以随意,当然最好能表达其作用。

      应用一     

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.anna.hello"
    android:sharedUserId="anna.uid">
  应用二
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.anna.world"
    android:sharedUserId="anna.uid">
  b) 两个应用程序设置完相同的UID之后,为了安全起见,建议再到Android.mk中定义相同的签名,因为如果不设置相同的签名,一旦
     应用被破解,所设置的UID被暴露,其它应用通过设定相同的UID也可以任意访问我们的数据,这样非安全的共享其实没有什么意义了,
     那么这个签名怎么设置呢?
     参考如下:
     vi Android.mk #应用一和应用二都需要添加
     将LOCAL_CERTIFICATE := testkey添加mk文件中
     可能在这里对于LOCAL_CERTIFICATE的赋值,大家又会有疑问,可以使用的值都有哪些呢?
     在build/target/product/security目录中有四组默认签名供Android.mk在编译APK使用:


1、testkey:普通APK,默认情况下使用。


2、platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。


3、shared:该APK需要和home/contacts进程共享数据。


4、media:该APK是media/download系统中的一环。


应用程序的Android.mk中有一个LOCAL_CERTIFICATE字段,由它指定用哪个key签名,未指定的默认用testkey
四组签名的原生注释可以查看build/target/product/security/README的说明。


  c)目前已经具备两个应用之间互相访问数据的权限,那么怎么互相访问呢?
     一方面是共享资源,要获取资源只要能拿到对方的context就可以,例如在应用二中创建应用一的context:
     Context context1 = this.createPackageContext(“test.anna.hello”,Context.CONTEXT_IGNORE_SECURITY);
     这里的this应该是Application或者Activity等有createPackageContext能力的类型相关实例。
     这样通过context1可以获取到应用一中的资源,包括:数据库,preference,资源文件等等
     例如通过context1获取应用一中的string:
     context1.getString(R.string.toast_message)


           其余资源获取方式查看Context的相关API进行使用。
     另一方面可能你还希望能够在应用二中使用应用一中的一些类,那么你可以通过修改应用二的Android.mk文件就可以mm通过,在该mk文件中添加如
     下这个编译变量的定义:
     LOCAL_APK_LIBRARIES += Hello  
     这样你可以编译通过,但是可能会有运行时错误,这个错误可能由于两个apk的classloader不一致,这个待后续验证再补充blog,今天累了。。。


参考:

1.http://www.cnblogs.com/perseus/articles/2354173.html

2.http://blog.youkuaiyun.com/wirelessqa/article/details/8581652

3.http://blog.youkuaiyun.com/hmg25/article/details/6447067




Android Studio 开发 APK 时添加 `android:sharedUserid="android.uid.system"` 属性可按以下方式操作: ### 在 AndroidManifest.xml 文件中添加属性 在 `AndroidManifest.xml` 文件的 `<manifest>` 节点中添加 `android:sharedUserId="android.uid.system"` 属性,示例如下: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" android:sharedUserId="android.uid.system"> <!-- 其他组件 --> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> ``` ### 在构建配置文件中配置签名 在 Android.mk 中增加 `LOCAL_CERTIFICATE := shared` 这种方式适用于传统的 Android 编译系统,在 Android Studio 中一般是通过 Gradle 构建系统,需要在 `build.gradle` 文件中配置签名信息。首先要准备好系统签名文件(如 testkey.x509.pem 和 testkey.pk8),然后在 `build.gradle` 文件中添加如下配置: ```groovy android { signingConfigs { release { storeFile file("path/to/your/keystore") storePassword "your_store_password" keyAlias "your_key_alias" keyPassword "your_key_password" } } buildTypes { release { signingConfig signingConfigs.release } } } ``` 注意,使用 `android:sharedUserId="android.uid.system"` 意味着此 APK 和系统拥有相同的 UID,可以共享系统资源,能加入同一进程中,但使用 Eclipse 编译、adb 安装调试时可能会报错;并且该属性默认会赋予应用所有权限,不利于颗粒化权限管控和区分数据流量,通常会收回各应用该权限,为每个应用预分配单独的 UID,一般不预分配 UID 也可正常运行 [^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值