sharedUserId
android:sharedUserId
sharedUserId的作用是让两个应用程序共享一个user id,我们都知道linux进程给每一个应用程序分配了一个独立的user id,所以如果两个或多个应用程序的签名相同并且设置了一样的sharedUserId,他们将会共享一个user id,相同user id的应用程序可以访问对方的数据(也就是说如果应用程序中的一个文件的权限是600,相同uid可以直接访问,反之则无法访问).
安装在设备中的每一个apk文件,Android给每个APK进程分配一个单独的用户空间,其manifest中的userid(userid的特点: 作为APK身份的标识 ;userid对应一个Linux用户,所以不同APK(用户)间互相访问数据默认是禁止的)就是对应一个Linux用户都会被分配到一个属于自己的统一的Linux用户ID,并且为它创建一个沙箱,以防止影响其他应用程序(或者其他应用程序影响它)。用户ID 在应用程序安装到设备中时被分配,并且在这个设备中保持它的永久性。所以让两个apk使用相同的userID,这样它们就可以看到对方的文件,如果在此基础之上再加上相同的android:process,他们就可以运行在一个进程中,能够做更多的事情了。为了节省资源,具有相同ID的apk也可以在相同的linux进程中进行(注意,并不是一定要在一个进程里面运行),共享一个虚拟机。
sharedUserId方式主要就是使用createPackageContext (String packageName, int flags)函数,该函数用来返回指定包名应用的上下文,注意是application的context。
这个方法有两个参数:
- packageName:包名,要得到Context的应用程序的完整包名
- flags:标志位,有CONTEXT_INCLUDE_CODE和CONTEXT_IGNORE_SECURITY两个选项,CONTEXT_INCLUDE_CODE选项的作用就是可以在调用者的进程执行该application的代码,也就是说可以使用getClassLoader()函数来初始化该application的相关类,使用该标识将会在你可以使用的application context上施加安全约束,如果需要加载的application不能被安全的加载进进程的话,将会抛出一个SecurityException,如果这个标示没有被设置,那么将不会在被加载的类上面施加任何约束,getClassLoader()将会返回默认的系统类加载器;CONTEXT_IGNORE_SECURITY的意思是忽略任何安全警告,和CONTEXT_INCLUDE_CODE标识一起使用可能会将不安全的代码加载进进程,所以谨慎使用。
在我博客android permission权限与安全机制解析(上)中已经简单介绍了一下SharedUserId,这次就要详细讲解一下他的具体用法,用来A应用和B应用之间的交互。先来看看两个应用的manifest文件:
A应用:
<manifest package="com.android.shareduserid_a"
xmlns:android="http://schemas.android.com/apk/res/android"
android:sharedUserId="com.android.test"
android:sharedUserLabel="@string/share_label">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name="com.android.shareuserid_a.Server">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
B应用:
<manifest package="com.android.shareduserid_b"
xmlns:android="http://schemas.android.com/apk/res/android"
android:sharedUserId="com.android.test"
android:sharedUserLabel="@string/share_label">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name="com.android.shareuserid_b.Client"
android:exported="true">
</activity>
</application>
</manifest>
B应用的Client Activity加上了android:exported=”true”用来与A应用交互,这个在android permission权限与安全机制解析(上)已经有详细的介绍,在这就略过了。
A应用有一个Server端的Activity,B应用有一个Client端的Activity,先来看看交互的效果,左侧为A应用,右侧为B应用:
A应用中的Server activity通过下面代码获取到B应用的application context:
context = createPackageContext("com.android.shareduserid_b", CONTEXT_INCLUDE_CODE|CONTEXT_IGNORE_SECURITY);
获取到该application的上下文之后,我们能做的事情就很多了,下面介绍几种:
获取B应用drawable
获取B应用的drawable,使用getIdentifier函数即可获取B应用该资源的id:
//获取B应用图片
int id = context.getResources().getIdentifier("share", "mipmap", "com.android.shareduserid_b");
iv_pic.setImageDrawable(ContextCompat.getDrawable(context, id));
获取B应用string
获取B应用字符串,统一使用getIdentifier函数获取id:
id = context.getResources().getIdentifier("share_string", "string", "com.android.shareduserid_b");
tv_string.setText(context.getString(id));
打开B应用页面
打开B应用activity,使用ComponentName设置B应用的activity名称和包名就能成功跳转过去了,类名需要带上完整的包名,当然使用intent.setClassName()函数也是能够成功的,记得在B应用一定要加上android:exported=”true”:
Intent intent = new Intent();
ComponentName componentName = new ComponentName("com.android.shareduserid_b",
"com.android.shareuserid_b.Client");
intent.setComponent(componentName);
//intent.setClassName(context, "com.android.shareuserid_b.Client");
//intent.setClassName("com.android.shareduserid_b",
// "com.android.shareuserid_b.Client");
startActivity(intent);
执行B应用指定类函数
执行B应用函数,当然是利用反射,要执行B应用的代码,调用createPackageContext函数时flag中一定要有CONTEXT_INCLUDE_CODE。如果被反射的函数参数是可变类型,类似于int… integers,那么getMethod函数第二个参数传入一个int[]数组就可以了。注意在B应用中要有相关的类和函数:
try {
Class clazz = context.getClassLoader().loadClass("com.android.shareuserid_b.Method");
Object object = clazz.newInstance();
int[] ints = new int[]{1,2,3};
int sum = (int) clazz.getMethod("add", int[].class).invoke(object, ints);
tv_sum.setText("sum is :"+sum);
} catch (Exception e) {
L.e(e);
e.printStackTrace();
}
获取B应用SharedPreferences
获取B应用SharedPreferences,这个需要特殊说明一下,由于SharedPreferences是有缓存机制的,所以如果在B应用中修改了该SharedPreferences文件,接着A应用去读取该文件中修改的那个值,这时你会发现还是修改前的值,这就是缓存机制导致的问题,不过有一个flag可以解决这个问题:MODE_MULTI_PROCESS,但是非常不幸的是api23已经将该标识deprecated了,原因是在一些版本上不可靠,有兴趣的可以去了解一下,看代码:
//注意Context.MODE_MULTI_PROCESS不可靠
SharedPreferences sharedPreferences = context.getSharedPreferences("permanent", MODE_MULTI_PROCESS);
String time = sharedPreferences.getString("time", "get time error");
tv_shared_preference.setText(time);
获取B应用数据库
获取B应用的数据库,注意数据库名字和表名一定要对应上,要不然会抛出Exception:
String DBPath = context.getDatabasePath("permanentCache.db").getAbsolutePath();
SQLiteDatabase sqLiteDatabase = SQLiteDatabase.openDatabase(DBPath, null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor = sqLiteDatabase.query("cache_1", null, "key=?", new String[]{"time"}, null, null, null, null);
cursor.moveToNext();
tv_DB.setText(cursor.getString(1));
cursor.close();
sqLiteDatabase.close();
用途:这种方式可以用来进行轻量级的补丁操作,例如皮肤,第一步从服务器获取所有皮肤的包名,第二步看用户选择的皮肤包是否已经安装到手机上,如果没有从服务器下载安装,如果有直接第三步;第三步当然就是从该皮肤包中获取资源等等等了。
下载地址
源码地址:https://github.com/zhaozepeng/IPC-demo/tree/master/ShareUserId
sharedUserId的更多相关文章
- Android如何通过shareduserid获取系统权限
[原文] android会为每个apk进程分配一个单独的空间(比如只能访问/data/data/自己包名下面的文件),一般情况下apk之间是禁止相互访问数据的.通过Shared User id,拥有同 ...
- android:sharedUserId 获取系统权限
最近在做的项目,有好大一部分都用到这个权限,修改系统时间啊,调用隐藏方法啊,系统关机重启啊,静默安装升级卸载应用等等,刚开始的时候,直接添加权限,运行就报错,无论模拟器还是真机,在logcat中总会得 ...
- Android中的sharedUserId属性详解
在Android里面每个app都有一个唯一的linux user ID,则这样权限就被设置成该应用程序的文件只对该用户可见,只对该应用程序自身可见,而我们可以使他们对其他的应用程序可见,这会使我们用到 ...
- Android权限之sharedUserId和签名
转自:http://blog.csdn.net/hmg25/article/details/6447067 最近在做个东西,巧合碰到了sharedUserId的问题,所以收集了一些资料,存存档备份. ...
- apk,task,android:process与android:sharedUserId的区别
apk一般占一个dalvik,一个进程,一个task.通过设置也可以多个进程,占多个task. task是一个activity的栈,其中"可能"含有来自多个App的activity ...
- Android sharedUserId 和系统权限
sharedUserId 给不同的应用使用同一个 sharedUserId 可以运行在这几个应用间互相访问数据(数据库,SharedPreferences,文件). sharedUserId 一旦使用 ...
- 【AndroidManifest.xml详解】Manifest属性之sharedUserId、sharedUserLabel
http://blog.csdn.net/wirelessqa/article/details/8581652 android:sharedUserId 当APK安装的时候,userid这个标志就会产 ...
- android:sharedUserId
<manifest> syntax: <manifest xmlns:android="http://schemas.android.com/apk/res/android ...
- Android sharedUserId 使用
在Android 系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系,.这个数字证书并不需要权威的数字证书签名机构认证,它只是用来让应用程 ...
随机推荐
- 【Swift 2.1】共享文件操作小结(iOS 8 +)
前言 适用于 iOS 8 + 本地共享文件列表 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblogs.com 农民伯伯: http://over140.cnblogs ...
- APP上架证书无效:解决
转发:http://www.cnblogs.com/pruple/p/5523767.html 转发:http://blog.csdn.net/sunnyboy9/article/details/50 ...
- android:使用RemoteView自定义Notification
//网上相关内容较少,遂记录下来,备忘. //依然以音乐播放器demo为例. 效果截图 //锤子手机上的效果 step1 准备自定义layout 常规的实现方式,并不会因为是用于notificatio ...
- 【转】Android Studio下加入百度地图的使用 (一)——环境搭建
最近有学 生要做毕业设计,会使用到定位及地图信息的功能,特此研究了一下,供大家参考,百度定位SDK已经更新到了5.0,地图SDK已经更新到了3.5,但是在 AndroidStudio中使用还是存在一些 ...
- HADOOP安装指南-Ubuntu15.10和hadoop2.7.2
Ubuntu15.10中安装hadoop2.7.2安装手册 太初 目录 1. Hadoop单点模式... 2 1.1 安装步骤... 2 0.环境和版本... 2 1.在ubu ...
- Crontab定时任务配置
CRONTAB概念/介绍 crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行. cron 系统调度进程. 可以使用它在 ...
- Reporting Service 服务启动时报错The service did not respond to the start or control request in a timely fashion
案例环境: 启动一台数据库服务器(Windows Server 2003)的Reporting Service(SQL Server 2008 R2)服务时,出现如下错误信息: System.Inva ...
- asp.net mvc 之旅—— 第三站 路由模板中强大的自定义IRouteConstraint约束
我们在写mvc的时候,经常会配置各种url模板,比如controller,action,id 组合模式,其实呢,我们还可以对这三个参数进行单独的配置,采用的方式自然 就是MapRoute中的const ...
- 不好的MySQL过程编写习惯
刚才为了测试一个东西,写了个存储过程: delimiter $$ drop procedure if exists sp_test$$ create procedure sp_test() begin ...
- UDT中epoll对CLOSE状态的处理
epoll_wait()返回可用uid时,对uid取状态,本该是BROKEN的,却取到CLOSED,然而,不能像处理BROKEN事件那样处理CLOSED事件,这样移除不了CLOSED事件,于是epol ...