这里总结一下在开发过程中,安卓高版本遇到的一些问题(持续更新中)。
1. Apache
在第三方登录时会出现一个错误:
Didn’t find class “org.apache.http.conn.scheme.SchemeRegistry” on path。
然后就闪退。
解决办法:
在Android6.0中,取消了对Apache HTTP客户端的支持。从Android9开始,默认情况下该内容库已从bootclasspath中移除且不可用于应用。要继续使用Apache Http客户端,从Android 9及更高版本为目标的应用可以向其AndroidManifest.xml中的application节点下添加以下内容:
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
注:拥有最低SDK版本23或更低版本的应用需要android:required="false"属性,因为在API级别低于24的设备上org.apache.http.legacy库不可用。
2. HTTP
前言:为保证用户数据和设备的安全,Google针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的连接,因此运行 Android P 系统的安卓设备无论是接收或者发送流量,未来都不能明码传输,需要使用下一代(Transport Layer Security)传输层安全协议,而 Android Nougat 和 Oreo 则不受影响。
因此在Android P 使用HttpUrlConnection进行http请求会出现以下异常:
W/System.err: java.io.IOException: Cleartext HTTP traffic to **** not permitted
使用OKHttp请求则出现:
java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy
在Android P系统的设备上,如果应用使用的是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,https则不会受影响,同样地,如果应用嵌套了webview,webview也只能使用https请求。
针对这个问题,有以下三种解决方法:
(1)APP改用https请求
(2)targetSdkVersion 降到27以下
(3)更改网络安全配置
前面两个方法容易理解和实现,具体说说第三种方法,更改网络安全配置。
1.在res文件夹下创建一个xml文件夹,然后创建一个network_security_config.xml文件,文件内容如下:
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
2.接着,在AndroidManifest.xml文件下的application标签增加以下属性:
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...
/>
完成,这个时候App就可以访问网络了。
(4)在AndroidManifest.xml配置文件的标签中直接插入
android:usesCleartextTraffic=“true”
3.读写
在Android Q版本及以上设备上文件读写可能会失败。究其原因是因为Android Q 默认开启沙箱模式导致出现文件读写失败,需要在使用动态权限申请的情况下在AndroidManifest.xml中加入
android:requestLegacyExternalStorage="true"
4. Android WorldWind截屏
Worldwind是继承自GLSurfaceView。GLSurfaceView 截取图像的时候,往往传统的方法并不行得通,我们发现使用GLSurfaceView.getDrawingCache() 等方法得到的往往是一张纯黑的图,这是由于 GLSurfaceView 和 SurfaceView 一样都有一块透明的缓存区域,所以我们截取的往往只是这块透明的缓存区域。
解决办法:
方法一:
下面这个方法是在 stackoverflow 上看到的一个方法,亲测可行。
private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl) {
int bitmapBuffer[] = new int[w * h];
int bitmapSource[] = new int[w * h];
IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
intBuffer.position(0);
try {
gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE,
intBuffer);
int offset1, offset2;
for (int i = 0; i < h; i++) {
offset1 = i * w;
offset2 = (h - i - 1) * w;
for (int j = 0; j < w; j++) {
int texturePixel = bitmapBuffer[offset1 + j];
int blue = (texturePixel >> 16) & 0xff;
int red = (texturePixel << 16) & 0x00ff0000;
int pixel = (texturePixel & 0xff00ff00) | red | blue;
bitmapSource[offset2 + j] = pixel;
}
}
} catch (GLException e) {
return null;
}
return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
}
截图的代码:
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// 获取GLSurfaceView的图片并保存
if (isTakePicture) {
Bitmap bmp = createBitmapFromGLSurface(0, 0, mOutputWidth,
mOutputHeight, gl);
isTakePicture = false;
}
因为onDrawFrame方法会被一直调用,所以我们需要控制一下截图的逻辑条件。
方法二:
这个方法也是我们项目中用到的一些截取图片的方法,也是可以用的。
private ByteBuffer mCaptureBuffer;
@Override
public void onDrawFrame(GL10 arg0) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
surfaceTexture.updateTexImage();
draw();
if (isTakePic) {
mCaptureBuffer.rewind();
GLES20.glReadPixels(0, 0, mOutputWidth, mOutputHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
mCaptureBuffer);
isTakePic = false;
new Thread(new Runnable() {
@Override
public void run() {
mCaptureBuffer.rewind();
mBitmap.copyPixelsFromBuffer(mCaptureBuffer);
String imageName = "Image_" + System.currentTimeMillis() + ".jpg";
BitmapUtils.saveBitmap(mBitmap, "/sdcard/face/", imageName);
}
}).start();
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mOutputWidth = width;
mOutputHeight = height;
mCaptureBuffer = ByteBuffer.allocate(mOutputWidth * mOutputHeight * 4);
mBitmap = Bitmap.createBitmap(mOutputWidth, height, Config.ARGB_8888);
GLES20.glViewport(0, 0, width, height);
mFilter.onOutputSizeChanged(width, height);
}
转载地址:https://blog.csdn.net/afei__/article/details/51614375
5.Android弹出悬浮窗,报“permission denied for window type”,的处理办法。
在Android系统中,如果应用需要弹出一个悬浮窗,就需要申请一项特殊权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
在Android O之前系统中申请了该权限后,再给对应的windows设置弹窗类型:
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_PHONE;
悬浮窗就可以显示出来了。
在Android O及更高版本上时,Google规定申请,悬浮窗的type需为:
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
悬浮窗才能显示出来,“TYPE_APPLICATION_OVERLAY”是重点。否则可能会造成闪退。
这里总结一下在开发过程中,安卓高版本遇到的一些问题(持续更新中)。