在升级Android targetSdkVersion 28的过程中,遇到了几个出现在Android 9.0的机器上的兼容性问题:
Apache HTTP 客户端弃用问题
Google Admob框架在9.0机器上报错:
Caused by java.lang.ClassNotFoundException
Didn't find class "org.apache.http.ProtocolVersion"
dalvik.system.BaseDexClassLoader.findClass (BaseDexClassLoader.java:134)
java.lang.ClassLoader.loadClass (ClassLoader.java:379)
ad.loadClass (ad.java:4)
java.lang.ClassLoader.loadClass (ClassLoader.java:312)
ly.b (ly.java:2)
lx.a (lx.java:1)
lz.a (lz.java:29)
com.google.android.gms.ads.internal.util.aq.a (aq.java:10)
lc.a (lc.java:8)
lc.run (lc.java:2)
这个是由于Apache HTTP 客户端弃用导致的问题,根据官方文档
),在AndroidManifest中加入以下配置即可:
<application>
<uses-library
android:name="org.apache.http.legacy"
android:required="false"/>
...
</application>
HTTP无法访问
根据官方文档, Android 9.0以上机器已经默认禁止HTTP明文通讯,所以在Android 9.0以上的机器targetSdkVersion>=28时会出现HTTP无法访问的问题,会抛出UnknownServiceException:
Cannot send data to the server
java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy
at
...
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:200)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:914)
解决方案
尽早切换至HTTPS,数据传输更加安全,同时HTTPS也是大势所趋,保不准以后会强制使用
在
AndroidManifest.xml中配置android:usesCleartextTraffic="true"
<application
...
android:usesCleartextTraffic="true">
这种方式相当于全局开启HTTP,允许访问所有的HTTP网址
- HTTP白名单配置
在res/xml中添加network_security_config.xml配置文件
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<!--http域名 or IP白名单-->
<domain includeSubdomains="true">secure.example.com</domain>
</domain-config>
</network-security-config>
然后在AndroidManifest.xml中指定该配置文件
<application
...
android:networkSecurityConfig="@xml/network_security_config">
Invalid Region.Op 问题
调用canvas.clipRect(newRect, Region.Op.REPLACE)方法时报错java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE
根据官方文档,该方法在API 26就已经废弃掉了,更可怕的是在API 28开始只支持Region.Op.INTERSECT 和 Region.Op.DIFFERENCE,说实话这种破坏性的API变更真有点操蛋,说好的向下兼容呢!

解决方案
只能通过判断API版本的方式来避免或者按照文档使用推荐的clipRect(android.graphics.Rect) or clipOutRect(android.graphics.Rect)来实现了
public class CanvasUtils{
public void safeClipRect(Canvas canvas, Rect rect, Region.Op op){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
canvas.clipRect(rect);
}else {
canvas.clipRect(rect, op);
}
}
}