1支示、系統(tǒng)簽名
當(dāng)項(xiàng)目開發(fā)需要使用系統(tǒng)級別權(quán)限或frame層某些api時刊橘,普通應(yīng)用是無法使用的,需要在AndroidManifest中配置sharedUserId:
android:sharedUserId="android.uid.system"
配置完 android:sharedUserId="android.uid.system" 之后颂鸿,此時的 app 是無法成功安裝到設(shè)備的促绵,控制臺會提示 INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,這是因?yàn)榇藭r app 已經(jīng)被識別為系統(tǒng)應(yīng)用嘴纺,但是其簽名信息卻不是系統(tǒng)簽名败晴,于是無法通過系統(tǒng)檢驗(yàn)。進(jìn)行系統(tǒng)簽名需要準(zhǔn)備好如下幾個文件:
- platform.pk8:簽名證書
- platform.x509.pem:簽名證書
- signapk.jar:簽名工具
注:我們是與Android系統(tǒng)廠商合作開發(fā)栽渴,以上文件為硬件廠商提供尖坤。
1.1 單獨(dú)簽名
將簽名文件和簽名工具、簽名apk放置同一目錄闲擦,定位到該目錄慢味,使用如下命令:
java -jar signapk.jar platform.x509.pem platform.pk8 unsign.apk signed.apk
signed.apk就是生成已經(jīng)擁有系統(tǒng)簽名的apk
1.2 生成平臺platform.keystore文件
除了直接使用signapk.jar簽名外,還可以將簽名文件生成keystore文件墅冷,然后給apk進(jìn)行簽名纯路。
1.2.1將pkcs8格式的私鑰轉(zhuǎn)化成pkcs12格式
openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out shared.priv.pem -nocrypt
1.2.2 將x509.pem公鑰轉(zhuǎn)換成pkcs12格式
openssl pkcs12 -export -in platform.x509.pem -inkey shared.priv.pem -out shared.pk12 -name test
這里會輸入密碼和確認(rèn)密碼,密碼是android
1.2.3 生成platform.keystore
keytool -importkeystore -deststorepass android -destkeypass android -destkeystore test.jks -srckeystore shared.pk12 -srcstoretype PKCS12 -srcstorepass android -alias test
1.2.4 引入AndroidStudio
配置項(xiàng)目builde.gradle寞忿,在android區(qū)域下(與defaultConfig同級)添加配置:
signingConfigs {
release {
storeFile file("../test")
storePassword 'android'
keyAlias 'test'
keyPassword 'android'
}
debug {
storeFile file("../test")
storePassword 'android'
keyAlias 'test'
keyPassword 'android'
}
}
2 代碼安裝
使用場景:版本更新
2.1 安裝方法
/*系統(tǒng)簽名apk 使用pm安裝*/
fun systemInstall(apkFile: File, finish: (() -> Unit)? = null) {
try {
if (apkFile.exists()) {
val cmd = "pm install -r " + apkFile.absolutePath
val runtime = Runtime.getRuntime()
val process = runtime.exec(cmd)
val errorInput = process.errorStream
val inputStream = process.inputStream
var bufferedReader = BufferedReader(InputStreamReader(inputStream))
var error = ""
var result = ""
var line = ""
while (bufferedReader.readLine().also { line = it } != null) {
result += line
}
bufferedReader = BufferedReader(InputStreamReader(errorInput))
while (bufferedReader.readLine().also { line = it } != null) {
error += line
}
Log.e("===>", result)
if (result == "Success") {
Log.e("===>", "install: Success")
} else {
Log.e("===>", "install: error$error")
}
finish?.invoke()
} else {
finish?.invoke()
}
} catch (e: IOException) {
e.printStackTrace()
finish?.invoke()
} catch (e: Exception) {
finish?.invoke()
}
}
2.2 注冊廣播驰唬,安裝成功后自啟
manifest文件下
<!-- 注冊廣播 安裝包更新調(diào)起自啟 -->
<receiver
android:name=".receiver.UpdateRestartReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
2.3 重啟app
public class UpdateRestartReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data != null && context.getPackageName().equals(data.getEncodedSchemeSpecificPart())) {
// 重新啟動APP
Intent intentToStart = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
context.startActivity(intentToStart);
}
}
}
}