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。 
  这个方法有两个参数:

  1. packageName:包名,要得到Context的应用程序的完整包名
  2. flags:标志位,有CONTEXT_INCLUDE_CODECONTEXT_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的更多相关文章

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

    [原文] android会为每个apk进程分配一个单独的空间(比如只能访问/data/data/自己包名下面的文件),一般情况下apk之间是禁止相互访问数据的.通过Shared User id,拥有同 ...

  2. android:sharedUserId 获取系统权限

    最近在做的项目,有好大一部分都用到这个权限,修改系统时间啊,调用隐藏方法啊,系统关机重启啊,静默安装升级卸载应用等等,刚开始的时候,直接添加权限,运行就报错,无论模拟器还是真机,在logcat中总会得 ...

  3. Android中的sharedUserId属性详解

    在Android里面每个app都有一个唯一的linux user ID,则这样权限就被设置成该应用程序的文件只对该用户可见,只对该应用程序自身可见,而我们可以使他们对其他的应用程序可见,这会使我们用到 ...

  4. Android权限之sharedUserId和签名

    转自:http://blog.csdn.net/hmg25/article/details/6447067 最近在做个东西,巧合碰到了sharedUserId的问题,所以收集了一些资料,存存档备份. ...

  5. apk,task,android:process与android:sharedUserId的区别

    apk一般占一个dalvik,一个进程,一个task.通过设置也可以多个进程,占多个task. task是一个activity的栈,其中"可能"含有来自多个App的activity ...

  6. Android sharedUserId 和系统权限

    sharedUserId 给不同的应用使用同一个 sharedUserId 可以运行在这几个应用间互相访问数据(数据库,SharedPreferences,文件). sharedUserId 一旦使用 ...

  7. 【AndroidManifest.xml详解】Manifest属性之sharedUserId、sharedUserLabel

    http://blog.csdn.net/wirelessqa/article/details/8581652 android:sharedUserId 当APK安装的时候,userid这个标志就会产 ...

  8. android:sharedUserId

    <manifest> syntax: <manifest xmlns:android="http://schemas.android.com/apk/res/android ...

  9. Android sharedUserId 使用

    在Android 系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系,.这个数字证书并不需要权威的数字证书签名机构认证,它只是用来让应用程 ...

随机推荐

  1. android gradle NDK简介

    本章介绍在Android开发中,关于NDK,gradle相关的知识点. 1.NDK简介 (1)NDK是一系列工具的集合 NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将s ...

  2. SSDT旧版本对于xml数据的处理BUG

    在早期版本中,CLR中声明sqlxml时,SSDT会将CLR函数中使用的类型解析为NVARCHAR(4000),最终导致传向CLR函数的数据不完整              

  3. StringBuilder用法

    //来自MSDN,不太懂英文可以使用百度翻译. //using System; //using System.Text; //public sealed class App //{ // static ...

  4. .NET应用程序调试—原理、工具、方法

    阅读目录: 1.背景介绍 2.基本原理(Windows调试工具箱..NET调试扩展SOS.DLL.SOSEX.DLL) 2.1.Windows调试工具箱 2.2..NET调试扩展包,SOS.DLL.S ...

  5. sql server2014不允许保存更改。阻止保存要求重新创建表的更改

    错误描述: SQL Server2014在原有的数据表中修改表结构后,保存数据表,提示错误如下: 不允许保存更改.您所做的更改要求删除并重新创建以下您对无法重新创建的表进行了更改或启用了"阻 ...

  6. sublime3 集成angularJs插件

    sublime是web开发中一款轻量级高效编辑器,十分适合前端开发(安装sublime是需要注册的,请支持正版) 1.安装sublime3(http://www.sublimetext.com/3) ...

  7. 问题解决——MFC resource.h 无法添加、提交到SVN

    =================================版权声明================================= 版权声明:原创文章 禁止转载  请通过右侧公告中的“联系邮 ...

  8. Linux From Scratch(从零开始构建Linux系统,简称LFS)- Version 7.7(二)

    七. 构建临时系统 1. 通用编译指南 a. 确认是否正确设置了 LFS 环境变量 echo $LFS b. 假定你已经正确地设置了宿主系统的符号链接: 1)shell 使用的是 bash. 2)sh ...

  9. 使用 python 实现 memcached 的启动服务脚本 rc

    #!/usr/bin/python #coding:utf-8 import sys import os from subprocess import Popen, PIPE class Memcac ...

  10. 关于Web报表FineReport打印的开发应用案例

    报表打印是报表使用和开发过程中经常碰到的问题,这里汇总了关于Web报表开发打印功能的一些典型应用案例,以应用最广泛的FineReport为例. 案例一:java直接调用报表打印 当java后台定义定时 ...