Android App相容8.0和9.0
Android在8.0限制了後臺服務這些,啟動後臺服務需要設定通知欄,使服務變成前臺服務。但是在9.0上,就會出現Permission Denial: startForeground requires android.permission.FOREGROUND_SERVICE
。
解決辦法是在AndroidManifest
中新增
<!--android 9.0上使用前臺服務,需要新增許可權-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
之後啟動service的時候也需要做處理,否則會拋異常java.lang.IllegalStateException: Not allowed to start service Intent
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
之後service的onCreate
還需要設定通知欄
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("xxx", "xxx", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (manager == null) return; manager.createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, "xxx") .setAutoCancel(true) .setCategory(Notification.CATEGORY_SERVICE) .setOngoing(true) .setPriority(NotificationManager.IMPORTANCE_LOW) .build(); startForeground(101, notification); }
服務這塊就沒了。stackoverflow的回答
專案中如果使用Volley的話,在android 9.0會出現異常,提示ProtocolVersion
的異常,之後,就在AndroidManifest
的application
節點下新增
<!--解決android9.0上使用ProtocolVersion拋異常的bug-->
<uses-library android:name="org.apache.http.legacy" android:required="false" />
之後編譯執行,請求網路正常了,不報錯了。
stackoverflow的相似問題
Android 9.0強制使用https,會阻塞http請求,如果app使用的第三方sdk有http,將全部被阻塞。
出現UnknownServiceException: CLEARTEXT communication to localhost not permitted by network security policy
或者IOException java.io.IOException: Cleartext HTTP traffic to * not permitted
就說明,你需要去相容了。最簡單的相容方式是在AndroidManifest
檔案的application
設定android:usesCleartextTraffic="true"
。這是第一種方式。
可以參考stackoverflow的回答
以及Android P - CLEARTEXT communication not permitted by network security policy
第二種方式:網路安全性配置
在AndroidManifest
檔案的application
節點配置android:networkSecurityConfig="@xml/network_security_config"
xml
中的配置具體的配置。
可以參考我的配置
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--預設配置,明文通訊,使用系統證書-->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!--trust system while release only-->
<certificates src="system" />
</trust-anchors>
</base-config>
<!--自己伺服器,使用https,將所有域名新增到此-->
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">xxx.xxx.com</domain>
<!--<trust-anchors>-->
<!--<certificates src="@raw/my_proxy_ssl_proxying_certificate" />-->
<!--</trust-anchors>-->
</domain-config>
<!--debug模式,可以使用使用者自己安裝的正式,比如charles抓包安裝的證書,這個配置只在 android:debuggable 為 "true" 時將應用的重寫,IDE 和構建工具生成的非釋出版本通常屬於此情況-->
<debug-overrides>
<!-- Trust user added CAs while debuggable only -->
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config>
第二種方式才是最好的方式,具體參考官方文件security-config
還有就是如果在請求https的時候丟擲javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
請檢查手機是不是設定了代理。android7.0之後不特殊處理,是無法抓取https。
把android官方文件放這裡,可以自己查閱通過https和SSL確保安全
補充記錄一個android 8.0的無法安裝apk,即 未知來源 的問題
8.0如果應用內有升級,而且應用沒有上google play ,安裝apk還需要申請 未知來源 的許可權
<!-- 8.0安裝apk許可權,需要允許安裝未知應用 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
安裝包下載完成之後,螢幕閃了一下並沒有跳轉到安裝介面,使用8.0以下的手機並沒有這個問題。
原因:Android 8.0 Oreo 中,Google 移除掉了容易被濫用的“允許位置來源”應用的開關,在安裝 Play Store 之外的第三方來源的 Android 應用的時候,竟然沒有了“允許未知來源”的檢查框,如果你還是想要安裝某個被自己所信任的開發者的 app,則需要在每一次都手動授予“安裝未知應用”的許可。
適配Android 8.0:
1.清單檔案新增安裝未知來源應用的許可權 android.permission.REQUEST_INSTALL_PACKAGES
2.下載好安裝包後,安裝程式之前驗證是否有安裝未知來源應用的許可權
public class MyActivity extends Activity {
private static final int REQUEST_INSTALL = 124;
private final UpdateBuilder builder = UpdateBuilder.create();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 請在Application中進行UpdateConfig的全域性配置
*/
builder.setInstallStrategy((context, s, update) -> {
if (Build.VERSION.SDK_INT < 26) {
//直接安裝
new DefaultInstallStrategy().install(context, s, update);
} else if (getPackageManager().canRequestPackageInstalls()) {//26 版本才有此方法
//可以安裝未知來源應用
new DefaultInstallStrategy().install(context, s, update);
} else {
//申請許可權
if (ActivityCompat.shouldShowRequestPermissionRationale(MyActivity.this, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
//自定義的Dialog,可以用Android系統自帶Dialog代替
new MessageDialog.Builder(UMainActivity.this)
.title("提示")
.content("為了正常升級“預逍”APP,請允許“預逍”安裝未知來源應用,本功能只限用於版本升級")
.positiveText("確定")
.negativeText("取消")
.canceledOnTouchOutside(false)
.cancelable(false)
.onPositive((dialog, which) -> ActivityCompat.requestPermissions(MyActivity.this,
new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES},
REQUEST_INSTALL))
.onNegative(((dialog, which) -> ActivityCompat.requestPermissions(MyActivity.this,
new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES},
REQUEST_INSTALL)))
.show();
} else {
ActivityCompat.requestPermissions(MyActivity.this,
new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES},
REQUEST_INSTALL);
}
}
});
builder.check();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_INSTALL) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
builder.check();
} else {
//啟動授權頁面
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_INSTALL);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_INSTALL) {
builder.check();
}
}
這個借鑑於github
8.0安裝閃退
慢慢踩坑
致敬前輩,砥礪前行!