Android sharedUserId研究记录

本文详细探讨了Android中的sharedUserId特性,通过设置相同sharedUserId,不同APK可以共享资源,包括数据目录、Resources和SharedPreferences。讨论了设置共享用户ID的方法,以及由此带来的资源共享、安全性及潜在问题,包括资源ID的处理和跨应用访问的安全性。同时提到了代码签名、调试安装和系统权限的相关内容。
摘要由CSDN通过智能技术生成

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

刚整理完的文档,顺便园子发个分享。因工作繁忙,还是有不少方面无法深入测试,欢迎各位回帖提出意见~

 

 

 

签名简介:

 

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

 

调试时,ADT会自动的使用debug密钥为应用程序签名。debug密钥是一个名为debug.keystore的文件,它的位置:系统盘符:/Documents and Settings/XXX/.android/debug.keystore  “XXX”对应于windows操作系统用户名。

 

主要涉及工具有三个,keytool、jarsigner和zipalign

 

 1)keytool:生成数字证书,即密钥,也就是上面说到的扩展名为.keystore的那类文件;
        2)jarsigner:使用数字证书给apk文件签名;
        3)zipalign:对签名后的apk进行优化,提高与Android系统交互的效率(Android SDK1.6版本开始包含此工具)

 

通常,可直接通过Ecplise的adt插件提供的功能来签名。(详细可见网络其他资源,本文主要讨论shareUserId)

 

 

 

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后,就可以互相访问了。代码如下。

 
  
//程序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();            }        }    }
 
 

 

 
  
//程序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的context            Context 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 {            fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);            //此处调用并没有区别,但context此时是从程序A里面获取的            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获取contex

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值