uni-app 离线打包可打开摄像头预览 但打包成插件在项目中无反应

uni-app 离线打包可打开摄像头预览 但打包成插件在项目中无反应

开发环境 版本号 项目创建方式
Windows HBuilderX

产品分类: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数据的字节数组
    }
}

更多关于uni-app 离线打包可打开摄像头预览 但打包成插件在项目中无反应的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于uni-app 离线打包可打开摄像头预览 但打包成插件在项目中无反应的实战教程也可以访问 https://www.itying.com/category-93-b0.html


uni-app 中,如果你在离线打包时能够正常打开摄像头预览,但将应用打包成插件并在主项目中使用时无法打开摄像头预览,可能的原因有以下几种:

1. 插件权限问题

  • 原因: 在主项目中,插件可能没有正确申请或获取摄像头权限。
  • 解决方案:
    • 确保在主项目的 manifest.json 文件中声明了摄像头权限。例如:
      {
          "permissions": {
              "camera": {}
          }
      }
      
    • 确保在插件代码中也正确请求了摄像头权限。例如:
      uni.authorize({
          scope: 'scope.camera',
          success() {
              console.log('Camera permission granted');
          },
          fail() {
              console.log('Camera permission denied');
          }
      });
回到顶部