Android 高版本遇到的那些坑

这里总结一下在开发过程中,安卓高版本遇到的一些问题(持续更新中)。
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文件,文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<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”是重点。否则可能会造成闪退。

这里总结一下在开发过程中,安卓高版本遇到的一些问题(持续更新中)。

猜你喜欢

转载自blog.csdn.net/nanjumufeng/article/details/123252554
今日推荐