Things That Cannnot Change(Android裏不能改變的東西)

原文鏈接


[本文作者Dianne Hackborn, 一位足跡遍佈所有安卓應用框架的工程師 - Tim Bray]

有時,一位開發者會對他的應用做一些改變(然後發佈新版本)。當新版本的應用覆蓋舊版的安裝時,發生了一些意想不到的結果——快捷方式失效,桌面小部件(鎖屏小部件)消失,甚至是應用根本無法覆蓋安裝。這是因爲,一個應用裏的某些部分在應用發佈後就不可改變。通過深入理解它們,你可以避免這些“意外”。

Your package name and certificate ( 包名和簽名 )

首先,最顯而易見的是“manifest裏的包名”,即你在app的AndoridManifest.xml裏定義獨特的包名。它遵循Java的包命名規則,使用你的個人(或公司)域名,避免命名衝突。舉個例子,自從谷歌擁有了“google.com”這個域名,谷歌的所有app就開始使用“com.google.xxx”作爲它的mainfest包名。對開發者來說,遵循這個命名規則極其重要,它有助於避免命名衝突。

一旦你發佈了你的應用,它manifest 裏的包名就是你應用永遠獨一無二的身份證明。如果包名進行了變更,新的app將無法覆蓋舊app(因爲它被識別爲一個全新的app)。

和包名同樣重要的還有app的簽名。簽名代表着app的作者,如果你改變一個app已經存在的簽名,該app就會因爲“作者”改變而被認爲是與原來完全不同的app。這個新的app發佈到市場時不能作爲原來app的升級版本,同理也不能在一臺Android設備上覆蓋安裝。

當用戶安裝一個被上述兩種改動之一改變過的app時,用戶看到的實際情況是不一樣的:

  • 若包名被更改,新app將會和舊app共存
  • 若簽名被更改,試圖安裝新app時將會提示安裝失敗,除非你能刪除該app的舊版本。

如果你改變了app的簽名,你應該同時改變其包名,避免它安裝失敗。換句話說,app的不同作者使其識別爲不同的應用,所以它的包名應進行合理地更改從而反應出這一情況。(當然,實驗性的項目使用相同的包名以及測試簽名是ok的,因爲它們並不會被髮布。)

Your AndroidManifest.xml is a public API ( AndroidManifest文件是公共的接口 )

事實上不只是你的包名是不可變的。AndroidManifest.xml 的一個主要功能是聲明app的public API,並提供給使用它的其他app和安卓系統。在Manifest裏聲明的每一個組件,都應被當做一個public API而不是private(即意味着它的android:exported 狀態是ture,能被其他程序調用)。同時它們不應被改變,否則在某種程度上就是破壞兼容性。

可能構成兼容性破壞的一個微小卻重要的部分就是 android:name 屬性,一般存在於activity,service,receiver等組件。這可能會令人驚訝,因爲我們總覺得 android:name 是指向我們實現app接口的私有屬性( as pointing to the private code implementing our application )。但是它同樣是這個組件的官方唯一public name ,作爲 ComponenName 類的具現。

改變app內部組件的命名將會對你的用戶帶來一些負面影響,如以下例子:

  • 若app主 activity name 被改變,用戶創建的快捷方式將無效。一個快捷方式就是直指它所要運行的組件名的Intent。
  • 若實現了 Live Wallpaper 的 service name 被改變,使用你的 Live Wallpaper 的用戶的壁紙會恢復到系統默認壁紙。同理,一些Input Methods,Accessibility Services,Honeycomb的新Widgets 等也會失效。
  • 若實現了Device Admin的receiver name 被更改,同上的Live Wallpaper例子, device admin將會失效。這結果同樣適用於其他receiver,比如app widget。

這些動作(即那些被做出的改變)是Android如何運用 Intent 系統的結果。有兩種主要的Intent:

  • 隱式Intent:只指定他們應該匹配“什麼”,做出什麼行動,分類,數據,MIME的類型等等。而他們真正要尋找的組件只在運行時去找,針對當前的app通過Package Manager匹配。
  • 顯式Intent:單一而明確指定它們通過組件名匹配“誰”。不管是什麼東西在Intent,它只和“準確的清單包名”以及“組件名給予的類名”相關聯。

兩種Intent類型在Android與你的app交互時都發揮了重要的的作用。一個典型的例子就是用戶是如何瀏覽和選擇動態壁紙。

爲了讓用戶能選擇一張動態壁紙,Android要做的第一件事就是顯示一個可用的動態壁紙服務列表給用戶。它爲動態壁紙創建一個隱式的Intent(包含一些適當的操作),然後向Package Manager請求所有能支持該Intent的services。而結果就是live wallpaper的列表展現給了用戶。

當用戶真的選擇了他們想要用的動態壁紙,此時Android卻需要創建一個顯式的Intent用來標識這張特別的動態壁紙,這就能告訴壁紙管理器該顯式那張壁紙。

這就是爲什麼改變manifest組件名會導致壁紙消失的原因:因爲組件名的引用已不存在,故預先存儲的顯式Intent現在也無效了。而我們沒有任何可用信息預測新的組件名是什麼(比如,假設你的app有兩個不同的動態壁紙服務可供用戶選擇)。所以,Android必須把那些動態壁紙當做已被卸載了,而後回到默認的壁紙。

這就是input methods, device administrators, account managers, app widgets, 以及application shortcuts 如何工作的原理。所以組件名是你在manifest裏聲明的公共且唯一的名字,並且在對其他app可見的情況下他們不允許更改。

總結:你的App裏有些部分是不可更改的,請務必小心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章