新增有原始碼apk到系統目錄下編譯(使應用擁有系統應用許可權)
阿新 • • 發佈:2019-01-09
需求
當我們的應用想要使用一些系統應用才能使用的功能時該怎麼辦呢?如何讓我們的應用“變成”系統應用? 現在我寫了一個測試demo,用於開啟GSP,但是2.3(還是2.1?)以後不允許三方應用直接開啟location開關。那我們該怎麼做呢?先不管應用系統(system app)的限制,我們照常寫app。許可權該新增的新增,即使出現下面的提示:
然後安裝執行,應用可能強退或者操作無響應。 大概log會提示
Caused by: java.lang.SecurityException:Permission denial: writing to settings requires:
2. 不帶原始碼直接放apk,mm編譯 3. 帶原始碼mm編譯 生成的apk放到system/app 或者priv-app目錄下,讓系統認為這是一個系統應用。
第1個方法最快,第2,3可以應用到預置apk的需求中。 下面我們分別說一下具體的步驟
1. 給應用系統簽名
說起來簡單也不簡單。說簡單因為就一條命令:java -jar signapk.jar platform.x509.pem platform.pk8 app-debug.
除了platform簽名以後還有 testkey media shared releasekey。 系統級別的簽名使用的是platform來簽名(此時使用android:sharedUserId="android.uid.system"才有用)。 但是使用的時候要注意,一定要使用和目標系統匹配的檔案來簽名。 比如我的原始碼目中有兩組platform簽名的檔案,我第一次簽名搞錯了(我沒發現有另一組在devices目錄下的檔案),所有才有了後面兩種方法的嘗試。
2. 不帶原始碼直接放apk,mm編譯
其實這一步也可以叫做“預置不帶原始碼的apk”。 1) 使用這種方法我們要為apk新建一個目錄(一般自己的應用預置在packages/apps目錄下,三方的可能在Vendor/third-party下), 2) 把apk放到目錄下 3) 編寫一個對應的Android.mk檔案。 這裡我們以googel translate.apk的預置為例,並以這個為參考編寫我們自己的Android.mk。 下面是Translate目錄下的Android.mk部分內容:# Translate
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE :=Translate
- LOCAL_MODULE_TAGS := optional
- LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
- LOCAL_MODULE_CLASS := APPS
- LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
- LOCAL_CERTIFICATE := PRESIGNED
- LOCAL_BUILT_MODULE_STEM := package.apk
- include $(BUILD_PREBUILT)
LOCAL_CERTIFICATE := platform
- LOCAL_PRIVILEGED_MODULE :=true
PRODUCT_PACKAGES += \
Books \
Bugle \
GoogleCamera \
3. 帶原始碼mm編譯
加入現在已經有一個使用Android Studio編寫的app了,我們想要把它的原始碼放到Android系統目錄下編譯,該如何做呢? 1) 跟2差不多,還是先建目錄已packages/app/目錄下面為例,新建一個ControlCenter的目錄, 2) 然後把原始碼全部放進去,然後把AndroidMainfest.xml複製到根目錄。 如果不做清理的話,目錄就是這個樣子的這裡提醒一下,如果要保持Android Studio Project的目錄格式的話,在用mm編譯前要把build目錄,test和androidTest目錄刪掉才能成功編譯。 如果有強迫症的話也可以刪除其他檔案,改成下面的樣子。
是不是簡潔了很多? 但是上面那種有個好處,既可以mm編譯,又可以單獨用Android Studio編譯。看自己需求。 3) 新建Android.mk檔案。貼一下Android.mk檔案內容:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
#將res移動到這個應用的根目錄
#LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
#如果你是Android Studio的res目錄
LOCAL_RESOURCE_DIR+= $(LOCAL_PATH)/app/src/main/res
#apk名字
LOCAL_PACKAGE_NAME :=ControlCenter
#系統簽名
LOCAL_CERTIFICATE := platform
#如果有使用到依賴
LOCAL_STATIC_JAVA_LIBRARIES:= \
android-support-v4
LOCAL_PRIVILEGED_MODULE :=true
include $(BUILD_PACKAGE)
期間遇到的問題
mm編譯不過 錯誤提示:packages/apps/ControlCenter/res/layout/activity_main.xml:14: error:Error:This attribute must be localized.(at 'text' with value 'wifi').
<Switch
android:id="@+id/switch_wifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="wifi"
android:onClick="onSwitchClicked"/>
總結
到此為止我們的需求已經通過三種方法實現了。 在有簽名檔案的情況下第一種方法最快捷。 第二種方法適合沒有原始碼的情況,或者app已經穩定不需要修改的情況下。而且可以預置到系統中。 第三種方法適合有原始碼,而且這個app可能隨時調整的情況。擴充套件
一些Android.mk引數說明: LOCAL_PATH:= $(call my-dir) 一個Android.mk file首先必須定義好LOCAL_PATH變數。它用於在開發樹中查詢原始檔。巨集函式’my-dir’,由編譯系統提供,用於返回當前路徑(即包含Android.mk file檔案的目錄)。
#begin 在加入這個巨集之前apk在/system/app下 #LOCAL_PRIVILEGED_MODULE := true #end 加入後apk在/system/priv-app下 #這個巨集控制的是apk可解除安裝,恢復出廠設定後無法恢復 #LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) #這個巨集控制系統給apk簽名 LOCAL_CERTIFICATE := PRESIGNED #這個巨集控制的是apk可解除安裝,恢復出廠設定後可以恢復 LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app Android.mk中可以定義多個編譯模組,每個編譯模組都是以include $(CLEAR_VARS)開始,以include $(BUILD_XXX)結束(詳解參考文末第二個連結)。
LOCAL_MODULE_TAGS := optional 解析: LOCAL_MODULE_TAGS :=user eng tests optional user: 指該模組只在user版本下才編譯
eng: 指該模組只在eng版本下才編譯
tests: 指該模組只在tests版本下才編譯
optional:指該模組在所有版本下都編譯
取值範圍debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要預裝,則應定義core.mk。