2012-01-25 25 views
2

我有一個應用程序使用應用程序包中包含的服務。如何選擇處理意圖的服務

我現在正在製作一個新的應用程序,它使用與它自己的應用程序包中捆綁的相同服務的更新版本。

如果只有一個應用程序安裝在設備上,這工作正常。但是,如果兩個應用程序都安裝在設備上,則它們都使用來自最近安裝最少的軟件包的服務 - 即最舊的軟件包。這是有問題的原因有兩個: 1)舊服務不處理新呼叫(顯然) 2)當使用與其他應用程序捆綁在一起的服務時,服務最終使用該其他應用程序的已保存數據而不是它自己的。

短期來看,我真的只希望每個應用都能與自己的服務版本進行交流。是否可以做到這一點,而不是讓每個捆綁服務都響應一個獨特的意圖,並讓每個應用程序使用這個獨特的意圖?

長期來看,可以選擇讓兩個應用都與最新版本的服務對話,並讓他們共享數據,並且可以很好地與兩個卸載的應用打好關係。什麼是正確的方式來做到這一點?數據主要位於SQLite數據庫中,該數據庫存儲在Context.getDatabasePath()指定的位置,這當然是特定於應用程序的,如果卸載該應用程序,則會被擦除。

這裏是我試過到目前爲止:

我可以使用PackageManager.queryIntentServices()獲得ResolveInfo列表與服務的兩個版本。通過查看ResolveInfo.serviceInfo.applicationInfo.packageName,我可以判斷哪個是哪個。但是,似乎沒有任何方法可以使用該ResolveInfo來指定我想要處理意圖的兩個服務中的哪一個。

這似乎是它應該做的事情:

serviceIntent.setPackage(context.getApplicationContext().getApplicationInfo().packageName); 

爲的packageName是一樣的一個我想匹配。事實上,當我打電話給queryIntentServices這個修改後的意圖時,我得到一個只包含我的包中的服務的列表。但是,當我嘗試使用該意圖綁定服務時,它會引發安全異常。

java.lang.RuntimeException: Unable to bind to service [email protected] with Intent { act=my.intent.string pkg=my.app.package.name }: java.lang.SecurityException: Not allowed to start service Intent { act=RuntimeException: Unable to bind to service my.service.package.name.MyServiceClass } without permission private to package 

基於一些google搜索,我也試圖通過做創建的意圖:

Intent serviceIntent = new Intent().setClassName(
    "my.service.package.name", 
    "my.service.package.name.ServiceClassName"); 

但這並不解決任何服務。

我也嘗試將AndroidManifest.xml中的服務條目中的android:exported=更改爲true,false或未指定,在兩個應用程序中以各種組合進行無效。 (我希望如果我將它們都設置爲false,那麼每個應用程序只能看到它自己的服務副本。)

+0

我發現上面的一個問題。對於Intent.setClassName()方法,它應該是: 'serviceIntent = new Intent()。setClassName( context.getApplicationContext()。getApplicationInfo()。packageName, 「my.service.package.name .ServiceClassName「);' 解析爲一個服務,正確的服務,但嘗試綁定該服務會引發與使用'Intent.setPackage()'相同的安全異常。 – benkc

回答

3

這是一個可以工作的解決方案:

在清單中爲服務添加元數據。該名稱應該像「服務啓動器」一樣,並且該值必須與意圖過濾器中的動作名稱相同。

<meta-data android:name="Service Launcher" 
      android:value="your.service.action.string.here" /> 

<intent-filter> 
    <action android:name="your.service.action.string.here" /> 
</intent-filter> 

然後在您的代碼中添加一個訪問方法來獲取元數據並使用它來構建Intent。

public static String getServiceIntentAction(Context context) { 
    String action = ""; 
    try { 
     PackageManager pm = context.getPackageManager(); 
     android.content.ComponentName cn = new android.content.ComponentName(context.getPackageName(), "com.your.ServiceClass"); 
     android.content.pm.ServiceInfo si = pm.getServiceInfo(cn, PackageManager.GET_META_DATA); 
     action = si.metaData.getString("Service Launcher"); 
    } catch(android.content.pm.PackageManager.NameNotFoundException nnfe) {} 
    return action; 
} 

然後什麼,正在建設的意圖,推出的服務調用此方法。該應用程序中的每個服務用戶都可以採取不同的操作,僅通過一個版本的庫與應用程序通信,而僅更改清單。

要讓這兩個應用程序使用相同的服務,服務應該可以作爲自己的實體安裝。

0

您是否嘗試過使用類別?對於意圖中的每個類別,潛在接收組件必須匹配每個類別才能被視爲接收者。

服務A有類別「1」,意向到類別「1」去那裏。 服務B具有類別「1」和類別「2」(假設它仍然支持版本「1」中的所有內容)有了這個,較舊的應用程序可以與較新的服務對話,但較新的應用程序不能與舊服務進行通信。

+0

因此,我可以強制新應用程序使用新版本的服務,但舊應用程序仍然會使用基於安裝順序的任意服務和數據。 (除非我只向服務A添加「1但不是2」的類別,但那樣會很糟糕。) – benkc

相關問題