1. 程式人生 > >通過Android manifest中的sharedUserId屬性的設定來實現apk之間的資源共享

通過Android manifest中的sharedUserId屬性的設定來實現apk之間的資源共享

在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.csdn.net/wirelessqa/article/details/8581652

3.http://blog.csdn.net/hmg25/article/details/6447067