赞
踩
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
。stackoverflow的回答
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安装闪退
慢慢踩坑
致敬前辈,砥砺前行!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。