2***@qq.com
2***@qq.com
  • 发布:2024-04-16 15:22
  • 更新:2024-04-16 15:22
  • 阅读:91

【报Bug】app离线打包可以打开摄像头预览但是打包成插件在uniapp项目中却没有反应

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: window10

HBuilderX类型: 正式

HBuilderX版本号: 4.08

手机系统: Android

手机系统版本号: Android 7.1.1

手机厂商: 模拟器

手机机型: 模拟器

页面类型: nvue

vue版本: vue3

打包方式: 云端

项目创建方式: HBuilderX

示例代码:

package com.test.myidentify;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
import android.os.HandlerThread;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import io.dcloud.feature.uniapp.UniSDKInstance;
import io.dcloud.feature.uniapp.ui.action.AbsComponentData;
import io.dcloud.feature.uniapp.ui.component.AbsVContainer;
import io.dcloud.feature.uniapp.ui.component.UniComponent;

public class identifyModule extends UniComponent<FrameLayout> {

private TextureView textureView;  

//相机相关  
private CameraManager cameraManager;  
private CameraDevice cameraDevice;  
private CameraCaptureSession cameraCaptureSession;  
private HandlerThread backgroundThread;  
private Handler backgroundHandler;  
private ImageReader imageReader;  
private Bitmap mCameraImage;  

public identifyModule(UniSDKInstance uniSDKInstance, AbsVContainer absVContainer, AbsComponentData absComponentData) {  
    super(uniSDKInstance, absVContainer, absComponentData);  
}  

@Override  
protected FrameLayout initComponentHostView(@NonNull Context context) {  
    textureView = new TextureView(context);  
    FrameLayout frameLayout = new FrameLayout(context);  
    frameLayout.setBackgroundColor(Color.BLACK);  
    frameLayout.addView(textureView);  
    boolean res = checkPermissions(); //检查权限  
    if(res) {  
        initializeCamera();  
    }  
    return frameLayout;  
}  

private static int PERMISSION_REQUEST_CODE = 1000;  
//加入要使用的权限  
protected static final String[] permissions = {  
        Manifest.permission.CAMERA, //相机摄像头权限  
        Manifest.permission.READ_PHONE_STATE, //读取电话状态  
        Manifest.permission.WRITE_EXTERNAL_STORAGE, //读写设备外部存储的文件,例如读取照片、音乐、视频等文件  
        Manifest.permission.READ_EXTERNAL_STORAGE, //读取外部存储中的内容  
};  

//检查权限  
private boolean checkPermissions() {  
    Context context = getContext();// 获取上下文  
    boolean check = true;  
    if (context instanceof Activity) {  
        Activity activity = (Activity) context;  
        // 相机权限尚未被授予  
        List<String> needRequestPermissionList = new ArrayList<String>();  
        for (String perm : permissions) {  
            if (ContextCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) {  
                needRequestPermissionList.add(perm);  
                check = false;  
            } else {  
                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, perm)) {  
                    needRequestPermissionList.add(perm);  
                }  
            }  
        }  
        if (needRequestPermissionList.size() > 0) {  
            ActivityCompat.requestPermissions(  
                    activity,  
                    needRequestPermissionList.toArray(new String[needRequestPermissionList.size()]),  
                    PERMISSION_REQUEST_CODE);  
        }  
    }  
    return check;  
}  

private static final int REQUEST_CAMERA_PERMISSION = 1000;  
// 处理相机权限请求的回调  
@Override  
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {  
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);  
    if(requestCode == REQUEST_CAMERA_PERMISSION) {  
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  
            initializeCamera();  
        }  
    }  
}  

// 初始化CameraManager和打开相机  
public void initializeCamera() {  
    cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);  
    try {  
        // 选择相机ID,这里假设使用第一个后置摄像头  
        String cameraId = cameraManager.getCameraIdList()[0];  
        if (ActivityCompat.checkSelfPermission(MyApplication.context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {  
            return;  
        }  
        cameraManager.openCamera(cameraId, stateCallback, backgroundHandler);  
    } catch (CameraAccessException e) {  
        e.printStackTrace();  
    }  
}  

private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {  

    @Override  
    public void onOpened(@NonNull CameraDevice camera) {  
        cameraDevice = camera;  
        createCameraCaptureSession();  
    }  

    @Override  
    public void onDisconnected(@NonNull CameraDevice camera) {  
        camera.close();  
        cameraDevice = null;  
    }  

    @Override  
    public void onError(@NonNull CameraDevice camera, int i) {  
        camera.close();  
        cameraDevice = null;  
    }  
};  

//创建相机捕获会话  
private void createCameraCaptureSession() {  
    try {  
        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();// 获取TextureView的SurfaceTexture  
        surfaceTexture.setDefaultBufferSize(640, 480);// 设置SurfaceTexture的一些属性  
        imageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2);  

        // 处理捕获的图像数据的回调  
        imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {  
            @Override  
            public void onImageAvailable(ImageReader reader) {  
                Image image = null;  
                try {  
                    image = reader.acquireLatestImage();  
                    if (image != null) {  
                        mCameraImage = yuv420ToBitmap(image);  
                    }  
                } catch (Exception e) {  
                    Log.e("====", "Error converting YUV to Bitmap", e);  
                } finally {  
                    if (image != null) {  
                        image.close();  
                    }  
                }  
            }  
        }, backgroundHandler);  

        // 将ImageReader的Surface设置给预览请求构建器  
        final CaptureRequest.Builder captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);  
        captureRequest.addTarget(new Surface(surfaceTexture));  
        captureRequest.addTarget(imageReader.getSurface());  
        cameraDevice.createCaptureSession(Arrays.asList(new Surface(surfaceTexture), imageReader.getSurface()),  
                new CameraCaptureSession.StateCallback() {  

                    @Override  
                    public void onConfigured(@NonNull CameraCaptureSession session) {  
                        try {  
                            cameraCaptureSession = session;  
                            captureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);  
                            cameraCaptureSession.setRepeatingRequest(captureRequest.build(), null, backgroundHandler);  
                        } catch (CameraAccessException e) {  
                            e.printStackTrace();  
                        }  
                    }  

                    @Override  
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {  
                        // 处理配置失败的情况  
                    }  
                },  
                backgroundHandler  
        );  

    } catch (CameraAccessException e) {  
        e.printStackTrace();  
    }  
}  

//将YUV格式的Image转换为Bitmap  
private Bitmap yuv420ToBitmap(Image image) {  
    RenderScript rs = RenderScript.create(MyApplication.context);  
    ScriptIntrinsicYuvToRGB script = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));  
    byte[] yuvByteArray = image2byteArray(image);  
    //创建了两个Allocation对象:一个用于输入YUV数据,另一个用于输出RGB数据  
    Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(yuvByteArray.length);  
    Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);  

    Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs))  
            .setX(image.getWidth())  
            .setY(image.getHeight());  
    Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);  
    //将YUV数据复制到输入Allocation,RenderScript可以访问  
    in.copyFrom(yuvByteArray);  
    script.setInput(in);  
    script.forEach(out);  

    Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);  
    out.copyTo(bitmap);  
    return bitmap;  
}  

//Image对象转换为一个包含YUV_420_888数据的字节数组  
public static byte[] image2byteArray(Image image) {  
    Image.Plane[] planes = image.getPlanes();// 获取Image的平面  
    ByteBuffer yBuffer = planes[0].getBuffer();  
    ByteBuffer uBuffer = planes[1].getBuffer();  
    ByteBuffer vBuffer = planes[2].getBuffer();  
    // 获取每个平面的数据长度  
    int ySize = yBuffer.remaining();  
    int uSize = uBuffer.remaining();  
    int vSize = vBuffer.remaining();  
    int yuvSize = ySize + uSize + vSize;// 计算YUV_420_888格式的总字节大小  
    byte[] yuvBytes = new byte[yuvSize];// 创建一个足够大的字节数组来存储YUV_420_888数据  
    yBuffer.get(yuvBytes, 0, ySize);// 将Y平面的数据复制到字节数组中  
    int uvIndex = ySize;// 计算U和V平面在YUV_420_888格式中的起始位置  
    uBuffer.get(yuvBytes, uvIndex, uSize);// 将U平面的数据复制到字节数组中  
    int vIndex = uvIndex + uSize;// 计算V平面在YUV_420_888格式中的起始位置  
    vBuffer.get(yuvBytes, vIndex, vSize);// 将V平面的数据复制到字节数组中  
    return yuvBytes;// 返回包含YUV_420_888数据的字节数组  
}  

}

操作步骤:

插件放入uniapp中进行自定义基座打包

预期结果:

运行uniapp项目打开相机实时预览

实际结果:

运行uniapp项目后无反应没有报错信息

bug描述:

app离线打包在Android studio中运行可以打开相机预览,打包成插件在uniapp中运行无反应

2024-04-16 15:22 负责人:无 分享
已邀请:

要回复问题请先登录注册