2010年12月24日 星期五

[Android] Getting package signature in runtime

如果使用過Google MapView你會發現G社會叫你用你的package signature去申請map key(參考這邊)

那MapView本身又是如何取得你的package signature的呢? 

其實很簡單, 可以透過目前的Context用Context.getPackageName()取得package name, 然後再利用package name去PackageManager.getPackageInfo()去查詢package的資訊(PackageInfo), 裡面有項資訊"signatures"就是我們所要的(一個package是可以被sign多次的)

Facebook Android SDK所提供的Single sign on (SSO)也是得先在server端註冊你的package signature, 這樣它可以避免別人偷用你的API key去做single sign on的動作(因為別人的AP可能不會跟你sign同一個signature)

但Facebook的SSO是透過Facebook for Android來做login的動作的, 你的application是透過startActivityForResult去叫Facebook for Android, 這牽涉到兩個不同的package, 如果依上面的例子的話, MapView其實是鑲嵌在你的UI上, 跟你的application是同一個package, 所以可以拿context來取得這資訊

Facebook for Android是如何取得call他的人的signature呢?

其實也是用PackageManager.getPackageInfo() 來取得, 但它如何知道呼叫他的人是哪個package的?

這只要組合兩個API就可以辦到了

第一個是Binder.getCallingUid() , 這可以讓你取得你的Calling process的UID

第二個是PackageManager.getPackagesForUid() , 這可以讓你取得屬於這UID的所有package

或許這邊你可能會有點疑問, 不是不同的package可以share UID嗎? 這樣取出來的package可能有很多個, 我怎知道用哪個? 我們目的只是要取得signature, 所以用哪個都一樣, 因為share UID的必要條件就是這些相同UID的package都是要sign同一把key, 所以只要找出所有package共通的signature就大功告成了