Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1304504
  • 博文数量: 478
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4833
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-28 11:12
文章分类

全部博文(478)

文章存档

2019年(1)

2018年(27)

2017年(21)

2016年(171)

2015年(258)

我的朋友

分类: Android平台

2016-03-22 17:57:52


1. 概述:
权限sharedUserId 与 LOCAL_CERTIFICATE ,在某些时候(较少)需要搭配使用。但若搭配错误,将带来令人费解的错误。
sharedUserId:来自于 manifest.xml;
[
用来限定在某种权限(通过LOCAL_CERTIFICATE来指定)下,
某些应用可以共同运行于某一进程(通过sharedUserId来配置或指定)
]
LOCAL_CERTIFICATE:来自于Android.mk;
[
用来限定应用程序的某种权限;
]

2. Manifest.xml 中的 sharedUserId语法


[html] view plaincopy
  1. <manifest xmlns:android=""            
  2.     package="string"            
  3.     android:sharedUserId="string"            
  4.     android:sharedUserLabel="string resource"            
  5.     android:versionCode="integer"            
  6.     android:versionName="string"            
  7.     android:installLocation=["auto" | "internalOnly" | "preferExternal"] >   
  8.      . . .  
  9. manifest>  





Package:命名,应用程序标识,缺省的进程名,缺省的活动的任务亲合力,不要变更,否则升级难。

sharedUserId:用来与其它应用程序共享(进程)的Linux用户ID名;

certificate & sharedUserId相同时,可运行于同一进程,且互相存取数据

sharedUserLabel:在设置上参数情况下,用户ID的可读名,且必须为资源的引用。

VersionCode:内部人员使用的版本号

versionName:用户可见的版本号

installLocation:安装位置: 缺省情况下:你的应用只能安装在内部空间,除非标为后二者其一。

当应用安装在外部时:

APK文件在外存,但应用程序数据仍在内存;

装有APK的SD卡将被标记,所以可以一机多卡,但不可多机一卡来使用装在SD卡上的APK应用。

详细请见(App Install Location);


3. 关于userid

    

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

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


对于一个APK来说,如果要使用某个共享UID的话,必须做三步:

1、在Manifest节点中增加android:sharedUserId属性。

2、在Android.mk中增加LOCAL_CERTIFICATE的定义。

如果增加了上面的属性但没有定义与之对应的LOCAL_CERTIFICATE的话,APK是安装不上去的。提示错误是:Package com.test.MyTest has no signatures that match those in shared user android.uid.system; ignoring!也就是说,仅有相同签名和相同sharedUserID标签的两个应用程序签名都会被分配相同的用户ID。例如所有和media/download相关的APK都使用android.media作为sharedUserId的话,那么它们必须有相同的签名media

3、把APK的源码放到packages/apps/目录下,用mm进行编译。


举例说明一下。

系统中所有使用android.uid.system作为共享UIDAPK,都会首先在manifest节点中增加android:sharedUserId="android.uid.system",然后在Android.mk中增加LOCAL_CERTIFICATE := platform。可以参见Settings

系统中所有使用android.uid.shared作为共享UIDAPK,都会在manifest节点中增加android:sharedUserId="android.uid.shared",然后在Android.mk中增加LOCAL_CERTIFICATE := shared。可以参见Launcher

系统中所有使用android.media作为共享UIDAPK,都会在manifest节点中增加android:sharedUserId="android.media",然后在Android.mk中增加LOCAL_CERTIFICATE := media。可以参见Gallery等。


另外,应用创建的任何文件都会被赋予应用的用户标识,并且正常情况下不能被其他包访问。当通过getSharedPreferencesStringint)、openFileOutputStringint)或者openOrCreate DatabaseStringintSQLiteDatabase.CursorFactory)创建一个新文件时,开发者可以同时或分别使用MODE_WORLD_READABLE MODE_WORLD_RITEABLE标志允许其他包读/写此文件。当设置了这些标志后,这个文件仍然属于自己的应用程序,但是它的全局读/写和读/写权限已经设置,所以其他任何应用程序可以看到它。


4. 关于签名:


build/target/product/security目录中有四组默认签名供Android.mk在编译APK使用:

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

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

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

4media:该APKmedia/download系统中的一环。

应用程序的Android.mk中有一个LOCAL_CERTIFICATE字段,由它指定用哪个key签名,未指定的默认用testkey.

 

 

对于使用eclipse编译的apk,可以使用signapk.jar来手动进行签名,其源码在build/tools/signapk下,编译后在out/host/linux-x86/framework/signapk.jar,也可以从网上下载。使用方法,以platform为例:java -jar ./signapkplatform.x509.pem platform.pk8 input.apk output.apk  (platform.x509.pem platform.pk8build/target/product/security获取)



5.  例一

MK中的ANDROID:SHAREDUSERIDLOCAL_CERTIFICATE作用

转自

Android中如何修改系统时间(应用程序获得系统权限) 
在 android API中有提供 SystemClock.setCurrentTimeMillis()函数来修改系统时间,可惜无论你怎么调用这个函数都是没用的,无论模拟器还是真 机,在logcat中总会得到"Unable to open alarm driver: Permission denied ".这个函数需要root权限或者运行与系统进程中才可以用。 
        本来以为就没有办法在应用程序这一层改系统时间了,后来在网上搜了好久,知道这个目的还是可以达到的。 
        第一个方法简单点,不过需要在Android系统源码的环境下用make来编译: 
        1. 在应用程序的AndroidManifest.xml中的manifest节点中加入android:sharedUserId="android.uid.system"这个属性。 
        2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行 
        3. 使用mm命令来编译,生成的apk就有修改系统时间的权限了。 
        第二个方法麻烦点,不过不用开虚拟机跑到源码环境下用make来编译: 
        1. 同上,加入android:sharedUserId="android.uid.system"这个属性。 
        2. 使用eclipse编译出apk文件,但是这个apk文件是不能用的。 
        3. 用压缩软件打开apk文件,删掉META-INF目录下的CERT.SFCERT.RSA两个文件。 
        4. 使用目标系统的platform密钥来重新给apk文件签名。这步比较麻烦,首先找到密钥文件,在我的Android源码目录中的位置 是"build\target\product\security",下面的platform.pk8platform.x509.pem两个文件。然 后用Android提供的Signapk工具来签名,signapk的源代码是在"build\tools\signapk"下,用法为"signapk platform.x509.pem platform.pk8 input.apk output.apk",文件名最好使用绝对路径防止找不到,也可以修改源代码直接使用。 
        这样最后得到的apk和第一个方法是一样的。 
        最后解释一下原理,首先加入android:sharedUserId="android.uid.system"这个属性。通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中。那么把程序的UID配成android.uid.system,也就是要让程序运行在系统进程中,这样就 有权限来修改系统时间了。 
        只是加入UID还不够,如果这时候安装APK的话发现无法安装,提示签名不符,原因是程序想要运行在系统进程中还要有目标系统的platform key,就是上面第二个方法提到的platform.pk8platform.x509.pem两个文件。用这两个key签名后apk才真正可以放入系 统进程中。第一个方法中加入LOCAL_CERTIFICATE := platform其实就是用这两个key来签名。 
        这也有一个问题,就是这样生成的程序只有在原始的Android系统或者是自己编译的系统中才可以用,因为这样的系统才可以拿到platform.pk8 platform.x509.pem两个文件。要是别家公司做的Android上连安装都安装不了。试试原始的Android中的key来签名,程序在 模拟器上运行OK,不过放到G3上安装直接提示"Package ... has no signatures that match those in shared user android.uid.system",这样也是保护了系统的安全。 
        最最后还说下,这个android:sharedUserId属性不只可以把apk放到系统进程中,也可以配置多个APK运行在一个进程中,这样可以共享数据,应该会很有用的。


6.  例二

Android-sharedUserId数据权限(转)

 

Android给每个APK进程分配一个单独的用户空间,manifest中的userid就是对应一个Linux用户
(Android 系统是基于Linux).
所以不同APK(用户)间互相访问数据默认是禁止的.
但是它也提供了2APK间共享数据的形式:
1. Share Preference. / Content Provider
APK可以指定接口和数据给任何其他APK读取需要自己实现接口和Share的数据.
本文对于这个不做详细解释

2. Shared User id
通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是
可以互相访问任意数据. 也可以配置成运行成不同的进程同时可以访问其他APK的数据目录下的
数据库和文件.就像访问本程序的数据一样.
比如某个公司开发了多个Android 程序那么可以把数据,图片等资源集中放到APK  A中去然后
这个公司的所有APK都使用同一个User ID, 那么所有的资源都可以从APK A中读取.

举个例子:
APK A APK B 都是C公司的产品,那么如果用户从APK A中登陆成功.那么打开APK B的时候就不用
再次登陆. 具体实现就是 AB设置成同一个User ID:
    * 2APKAndroidManifest.xml 配置User ID:
    
    package="com.android.demo.a1"
    android:sharedUserId="com.c">
   这个"com.c" 就是user id, 然后packagename APK A就是上面的内容,  APK B可能
   是"com.android.demo.b1" 这个没有限制

这个设定好之后, APK B就可以像打开本地数据库那样 打开APK A中的数据库了.
APK A把登陆信息存放在A的数据目录下面. APK B每次启动的时候读取APK A下面的数据库
判断是否已经登陆:
APK B中的代码:
            friendContext = this.createPackageContext(
                    "com.android.demo.a1",
                    Context.CONTEXT_IGNORE_SECURITY);
通过Apackage name 就可以得到A的 packagecontext
通过这个context就可以直接打开数据库



7. 例三

android 如何依赖android:sharedUserId更换皮肤Skin  

 为了更好的UI体验,不错的App都会有几套不错的SKIN提供给用户来选择,以下是两个比较简单的工程,一个为主工程.apk,一个为皮肤.apk

先看皮肤:

[html] view plaincopy
  1. AndroidMainfest.xml  
  2. xml version="1.0" encoding="utf-8"?>  
  3. <manifest xmlns:android=""        
  4.     package="com.tal.skin"       
  5.     android:versionCode="1"       
  6.     android:versionName="1.0"       
  7.     android:sharedUserId="com.tal.skinmain">①  
  8.         <uses-sdk android:minSdkVersion="7" />  
  9.             <application android:icon="@drawable/icon" android:label="@string/app_name">   
  10.                 <activity android:name=".Skin"                   
  11.                 android:label="@string/app_name">             
  12.                 <intent-filter>                
  13.                     <action android:name="android.intent.action.MAIN" />    
  14.                             <category android:name="android.intent.category.LAUNCHER" />       
  15.                     intent-filter>      
  16.                 activity>    
  17.         application>  
  18. manifest>  



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

然后再皮肤工程里面放置两张图片,来显示替换皮肤样式。skin1.png,skin2.png

皮肤工程无需activity界面即可;

主工程:

AndroidMainfest.xml按照正常写法即可,无需配置什么东东,当时在设置皮肤的需要这样写上:

[java] view plaincopy
  1. "code" class="java">"code" class="java">package com.tal.skinmain;  
  2. import com.tal.skin.R;  
  3. package com.tal.skinmain;  
  4. import com.tal.skin.R;  
  5. import android.app.Activity;  
  6. import android.content.Context;  
  7. import android.content.pm.PackageManager.NameNotFoundException;  
  8. import android.graphics.Color;  
  9. import android.os.Bundle;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13. import android.widget.LinearLayout;  
  14. import android.widget.TextView;  
  15. /** 
  16.  *  
  17.  *   @author Tal  
  18.  *   @time  2011-5-9下午09:32:47   
  19.  *   @Email dangzhengtao@gmail.com  
  20.  *   @tag   可以更换皮肤的主工程  
  21.  */  
  22.   
  23. public class SkinMain extends Activity {   
  24.     LinearLayout  linearLayout;   
  25.     TextView textview; Context ctx;  
  26.     Button bt1,bt2,bt3;  
  27.     boolean flag = true;    
  28.     /** Called when the activity is first created. */    
  29.     @Override      
  30.     public void onCreate(Bundle savedInstanceState) {   
  31.         super.onCreate(savedInstanceState);        
  32.         setContentView(R.layout.main);              
  33.         textview = (TextView)findViewById(R.id.id_skin_textview);    
  34.         textview.setText("皮肤一");        
  35.         linearLayout = (LinearLayout)findViewById(R.id.id_skin_linearlayout);    
  36.           
  37.         linearLayout.setBackgroundColor(Color.BLUE);        
  38.         try {    
  39.             //获取皮肤共享的数据包       
  40.             ctx = this.createPackageContext("com.tal.skin", CONTEXT_IGNORE_SECURITY);②   
  41.             } catch (NameNotFoundException e) {   
  42.                 // TODO Auto-generated catch block    
  43.                 e.printStackTrace();   
  44.             }       
  45.         bt1 = (Button)findViewById(R.id.id_skin_bt1);   
  46.         bt2 = (Button)findViewById(R.id.id_skin_bt2);   
  47.         bt3 = (Button)findViewById(R.id.id_skin_bt3);   
  48.         bt1.setOnClickListener(new OnClickListener(){    
  49.             @Override     
  50.             public void onClick(View v) {    
  51.                 linearLayout.setBackgroundColor(Color.BLUE);  
  52.                 textview.setText("默认皮肤");   }});   
  53.         bt2.setOnClickListener(new OnClickListener(){    
  54.             @Override     
  55.             public void onClick(View v) {   
  56.                 linearLayout.setBackgroundDrawable(ctx.getResources().getDrawable(R.drawable.skin1));  ③   
  57.                 textview.setText("皮肤一");   }});   
  58.         bt3.setOnClickListener(new OnClickListener(){     
  59.             @Override     
  60.             public void onClick(View v) {    
  61.                 linearLayout.setBackgroundDrawable(ctx.getResources().getDrawable(R.drawable.skin2));④    
  62.                 textview.setText("皮肤二");   }});   
  63.         }  
  64.     }  
  65. ///注解:②③④获取皮肤工程的数据,当中有指定皮肤的包名  
  66. }  

  67.   

  68.   
  69.   
  70.   
  71. main.xml

      

  72.   

  73.   
  74. "code" class="html">"code" class="html">"1.0" encoding="utf-8"?>  
  75. ""  
  76.     android:orientation="vertical" android:layout_width="fill_parent"  
  77.     android:layout_height="fill_parent" android:id="@+id/id_skin_linearlayout">  
  78.     "@+id/id_skin_textview"  
  79.         android:layout_width="fill_parent" android:layout_height="wrap_content"  
  80.         android:text="@string/hello" />  
  81.     "@+id/id_skin_bt1" android:layout_width="fill_parent"  
  82.         android:layout_height="wrap_content" android:text="默认" />  
  83.     "@+id/id_skin_bt2" android:layout_width="fill_parent"  
  84.         android:layout_height="wrap_content" android:text="皮肤一" />  
  85.     "@+id/id_skin_bt3" android:layout_width="fill_parent"  
  86.         android:layout_height="wrap_content" android:text="皮肤二" />  

  87.   

  88.   
  89.   
  90. class="p0" style="margin-bottom:0pt; margin-top:0pt; line-height:18.75pt">"color:rgb(105,105,105); font-size:10.5pt; font-family:Arial"> OK"font-family:宋体">。"color:rgb(105,105,105); font-size:10.5pt; font-family:Arial">

      
  91. class="p0" style="margin-bottom:7.5pt; margin-top:0pt; text-align:left; line-height:18.75pt">  
  92. "color:rgb(105,105,105); font-size:10.5pt; font-family:Arial">运行如图:"color:rgb(105,105,105); font-size:10.5pt; font-family:Arial">

      
  93. class="p0" style="margin-bottom:0pt; margin-top:0pt; text-align:left; line-height:18.75pt">  
  94.   
  95. class="p0" style="margin-bottom:0pt; margin-top:0pt">"" alt="">

      
  96. class="p0" style="margin-bottom:0pt; margin-top:0pt">

      
  97. class="p0" style="margin-bottom:0pt; margin-top:0pt">"" alt="">

      
  98. class="p0" style="margin-bottom:0pt; margin-top:0pt">

      
  99. class="p0" style="margin-bottom:0pt; margin-top:0pt">"" alt="">

      
  100. class="p0" style="margin-bottom:0pt; margin-top:0pt; text-align:left; line-height:18.75pt">  
  101. "color:rgb(105,105,105); font-family:Arial; font-size:10.5pt; line-height:18.75pt"

      
  102. class="p0" style="margin-bottom:0pt; margin-top:0pt; text-align:left; line-height:18.75pt">  
  103.   
  104. class="p0" style="margin-bottom:0pt; margin-top:0pt">"http://www.cnblogs.com/playing/archive/2011/06/15/2081260.html">"color:rgb(0,0,255); font-size:10.5pt; font-family:Arial">http://www.cnblogs.com/playing/archive/2011/06/15/2081260.html

      
  105.   
  106.   
  107.   
  108.   
  109.   
  110.   
  111.      
  112.  
阅读(1264) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~