2025-10-08 15:12 采纳率: 0%
浏览 17

uniapp项目标准基座正常,而云端打包的自定义基座在调用特定原生API时崩溃。

uniapp使用云端打包自定义基座时出现const MediaStore = plus.android.importClass("android.provider.MediaStore");执行出现问题导致模拟器上app直接刷新重新启动了没有继续执行下去只输出了1,2,3没有输出4,如果使用标准基座就没有问题,找不到问题原因感觉是云端打包没有接入这个类导致标准基座正常,而云端打包的自定义基座在调用特定原生API时崩溃。


```javascript
// 使用相册API的方法获取图片路径
    const usePhotoAlbumMethod = async () => {
        // handleStartKeepAlive()


        isExploring.value = true;
        errorMessage.value = '';
        scanInfo.value = '正在请求权限...'; // 提示用户正在请求权限


        // 重置数据
        directories.value = [];
        images.value = [];
        selectedDirectory.value = '';
        selectedDirectoryName.value = '';

        // #ifdef APP-PLUS
        // 关键步骤:首先请求权限
        const permissionGranted = await requestAndroidPermission();

        // 如果用户未授权,则直接停止
        if (permissionGranted !== 1) {
            errorMessage.value = '您没有授予读取相册的权限,无法扫描图片。';
            scanInfo.value = '权限请求被拒绝。';
            isExploring.value = false;
            uni.showToast({
                title: '需要相册权限',
                icon: 'none'
            });
            return; // 提前退出函数
        }
        // #endif

        scanInfo.value = '权限已授予,正在使用相册API获取图片信息...';

        try {
            // #ifdef APP-PLUS
            // 使用MediaStore API获取所有图片信息
            console.log(1);
            const context = plus.android.runtimeMainActivity();
            console.log(2);
            const ContentResolver = plus.android.importClass("android.content.ContentResolver");
            console.log(3);
            const MediaStore = plus.android.importClass("android.provider.MediaStore");
            console.log(4);
            const Cursor = plus.android.importClass("android.database.Cursor");
            console.log(5);
            // return;
            const contentResolver = context.getContentResolver();

            // 查询所有图片
            const projection = [
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.DISPLAY_NAME,
                MediaStore.Images.Media.DATA, // 文件路径
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME // 文件夹名称
            ];

            const cursor = contentResolver.query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                projection,
                null,
                null,
                MediaStore.Images.Media.DATE_ADDED + " DESC"
            );

            if (cursor && cursor.moveToFirst()) {
                const dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                const nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME);
                const bucketIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);

                let count = 0;
                do {
                    const filePath = cursor.getString(dataIndex);
                    const fileName = cursor.getString(nameIndex);
                    const bucketName = cursor.getString(bucketIndex);

                    if (filePath && fileName) {
                        // 检查文件是否存在
                        const File = plus.android.importClass("java.io.File");
                        const file = new File(filePath);

                        if (file.exists()) {
                            images.value.push({
                                name: fileName,
                                path: 'file://' + filePath,
                                bucket: bucketName || '未知文件夹'
                            });
                            count++;
                        }
                    }
                } while (cursor.moveToNext());

                cursor.close();
                scanInfo.value = `通过MediaStore API找到 ${count} 张图片`;
                console.log(`通过MediaStore API找到 ${count} 张图片`);
            }
            // #endif

            // #ifndef APP-PLUS
            scanInfo.value = '相册API功能仅在App环境中可用';
            // #endif

            // 生成目录列表
            generateDirectoriesFromImages();

        } catch (error) {
            console.error('使用相册API扫描失败:', error);
            errorMessage.value = '使用相册API扫描失败: ' + error.message;
        } finally {
            isExploring.value = false;
        }
    };



下面时manifest.json的配置


{
    "name" : "mmy",
    "appid" : "__UNI__6C099A7",
    "description" : "",
    "versionName" : "1.0.0",
    "versionCode" : 108,
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
        "usingComponents" : true,
        "nvueStyleCompiler" : "uni-app",
        "compilerVersion" : 3,
        "splashscreen" : {
            "alwaysShowBeforeRender" : true,
            "waiting" : true,
            "autoclose" : true,
            "delay" : 0
        },
        /* 模块配置 */
        "modules" : {
            "Camera" : {},
            "VideoPlayer" : {
                //可选,JSON对象,VideoPlayer(视频播放)
                "description" : "iBeacon"
            },
            "Webview-x5" : {
                //可选,JSON对象,Android X5 Webview(腾讯TBS),仅Android支持
                "description" : "iBeacon"
            },
            "UIWebview" : {
                //可选,JSON对象,UIWebview,仅iOS支持
                "description" : "iBeacon"
            },
            "IO" : {}, // 【必须添加】用于文件系统操作 (plus.io)
            "Runtime" : {}, // 【必须添加】用于原生调用 (plus.android)
            "Gallery" : {}, // 【强烈建议添加】用于相册功能 (uni.chooseImage)
            "Content" : {}
        },
        /* 应用发布信息 */
        "distribute" : {
            /* android打包配置 */
            "android" : {
                "permissions" : [
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
                    "<uses-feature android:name=\"android.hardware.camera\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
                    /*创建快捷方式*/
                    "<uses-permission android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\"/>",
                    "<uses-permission android:name=\"com.android.launcher.permission.UNINSTALL_SHORTCUT\"/>",
                    "<uses-permission android:name=\"com.android.launcher.permission.READ_SETTINGS\"/>",
                    "<uses-permission android:name=\"android.permission.INSTALL_SHORTCUT\"/>",
                    "<uses-permission android:name=\"android.permission.UNINSTALL_SHORTCUT\"/>",
                    /*文件目录读取*/
                    "<uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\"/>",
                    "<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
                    /*壁纸设置*/
                    "<uses-permission android:name=\"android.permission.SET_WALLPAPER\"/>",
                    "<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>",
                    /*后台权限*/
                    "<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />",
                    "<uses-permission android:name=\"android.permission.SCHEDULE_EXACT_ALARM\" />"
                ],
                "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ], // 同时支持32位和64位架构

                /* uts插件 */
                "plugins" : [
                     {
                         "name" : "t-keepalive-api", // 请再次确认这个ID是否正确
                         "type" : "uts"
                     }
                 ],
                "custompermissions" : false, //可选,Boolean类型,是否自定义Android权限配置
                "permissionExternalStorage" : {
                    //可选,JSON对象,Android平台应用启动时申请读写手机存储权限策略
                    "request" : "always", //必填,字符串类型,申请读写手机存储权限策略,可取值none、once、always
                    "prompt" : "" //可选,字符串类型,当request设置为always值用户拒绝时弹出提示框上的内容
                },
                "permissionPhoneState" : {
                    //可选,JSON对象,Android平台应用启动时申请读取设备信息权限配置
                    "request" : "always", //必填,字符串类型,申请读取设备信息权限策略,可取值none、once、always
                    "prompt" : "" //可选,字符串类型,当request设置为always值用户拒绝时弹出提示框上的内容
                }
            },
            /* ios打包配置 */
            "ios" : {
                "dSYMs" : false
            },
            /* SDK配置 */
            "sdkConfigs" : {}
        }
    },
    /* 快应用特有相关 */
    "quickapp" : {},
    /* 小程序特有相关 */
    "mp-weixin" : {
        "appid" : "",
        "setting" : {
            "urlCheck" : false
        },
        "usingComponents" : true
    },
    "mp-alipay" : {
        "usingComponents" : true
    },
    "mp-baidu" : {
        "usingComponents" : true
    },
    "mp-toutiao" : {
        "usingComponents" : true
    },
    "uniStatistics" : {
        "enable" : false
    },
    "vueVersion" : "3"
}

```

  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-10-08 15:26
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    你提到的问题是:在 UniApp 项目中,使用标准基座时调用 plus.android.importClass("android.provider.MediaStore") 没有问题,但使用云端打包的自定义基座时,执行到该语句后程序崩溃(模拟器重启),没有输出 console.log(4)

    这个问题的根本原因通常与 UniApp 云端打包配置不完整或缺少某些 Android 原生类依赖有关。


    ✅ 问题分析

    1. 标准基座 vs 自定义基座

      • 标准基座是 UniApp 提供的预编译版本,包含了大部分常用原生类和 API。
      • 自定义基座需要你在打包时手动指定所需的模块和依赖,如果未正确配置,可能导致部分原生类无法加载。
    2. MediaStore 类的缺失

      • MediaStore 是 Android 系统提供的一个类,用于访问媒体数据(如图片、视频等)。
      • 如果你的自定义基座没有包含这个类的引用,或者打包时未正确导入,就会导致运行时崩溃。
    3. plus.android.importClass() 的行为

      • 该方法在运行时尝试加载类,如果类不存在,会抛出异常,进而导致应用崩溃。
      • 在云端打包的自定义基座中,可能因为某些配置问题导致该类未被正确引入。

    ✅ 解决方案

    1. 确保自定义基座中包含所有必要的 Android 类

    • 检查打包配置文件(如 manifest.jsonunpackage.json 中的 distribute 配置):

      • 确保你已经启用了 “自定义基座” 功能。
      • distribute > android > custom 配置中,添加以下内容:
      {
        "distribute": {
          "android": {
            "custom": {
              "include": [
                "android.provider.MediaStore",
                "android.content.ContentResolver",
                "android.database.Cursor"
              ]
            }
          }
        }
      }
      
    • 注意:如果你使用的是 HBuilderX 或 DCloud 的打包服务,请在打包设置中勾选 “包含所有系统类”“启用全部 Android API”


    2. 确认是否在打包时开启了 plus 模块支持

    • manifest.jsonplus 节点中,确保如下配置存在:

      "plus": {
        "distribute": {
          "android": {
            "custom": {
              "enable": true
            }
          },
          "distribute": {
            "android": {
              "custom": {
                "include": ["*"]
              }
            }
          }
        }
      }
      

    3. 使用 try-catch 包裹关键代码以捕获错误

    虽然这不能解决根本问题,但可以防止应用直接崩溃,并帮助你定位错误来源。

    try {
        const MediaStore = plus.android.importClass("android.provider.MediaStore");
        console.log(4);
    } catch (e) {
        console.error("无法加载 MediaStore 类:", e);
        uni.showToast({
            title: "加载失败,请检查权限或重新打包",
            icon: "none"
        });
    }
    

    4. 检查权限是否正确申请

    • 即使 MediaStore 类加载成功,若未正确申请权限,也可能导致后续操作失败。

    • 请确保你的 AndroidManifest.xml 文件中包含以下权限:

      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      
    • 并且在运行时通过 plus.android.requestPermissions() 请求权限。


    5. 重新打包并测试

    • 修改完配置后,务必重新进行云端打包
    • 使用 真机调试模拟器 测试,观察是否仍然崩溃。

    ✅ 修改后的代码示例(加入异常处理)

    const usePhotoAlbumMethod = async () => {
        isExploring.value = true;
        errorMessage.value = '';
        scanInfo.value = '正在请求权限...';
    
        // #ifdef APP-PLUS
        try {
            const permissionGranted = await requestAndroidPermission();
    
            if (permissionGranted !== 1) {
                errorMessage.value = '您没有授予读取相册的权限,无法扫描图片。';
                scanInfo.value = '权限请求被拒绝。';
                isExploring.value = false;
                uni.showToast({ title: '需要相册权限', icon: 'none' });
                return;
            }
    
            scanInfo.value = '权限已授予,正在使用相册API获取图片信息...';
    
            console.log(1);
            const context = plus.android.runtimeMainActivity();
            console.log(2);
    
            try {
                const ContentResolver = plus.android.importClass("android.content.ContentResolver");
                console.log(3);
                const MediaStore = plus.android.importClass("android.provider.MediaStore");
                console.log(4);
                const Cursor = plus.android.importClass("android.database.Cursor");
                console.log(5);
    
                const contentResolver = context.getContentResolver();
                const projection = [
                    MediaStore.Images.Media._ID,
                    MediaStore.Images.Media.DISPLAY_NAME,
                    MediaStore.Images.Media.DATA,
                    MediaStore.Images.Media.BUCKET_DISPLAY_NAME
                ];
    
                const cursor = contentResolver.query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    projection,
                    null,
                    null,
                    MediaStore.Images.Media.DATE_ADDED + " DESC"
                );
    
                if (cursor && cursor.moveToFirst()) {
                    const dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                    const nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME);
                    const bucketIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
    
                    let count = 0;
                    do {
                        const filePath = cursor.getString(dataIndex);
                        const fileName = cursor.getString(nameIndex);
                        const bucketName = cursor.getString(bucketIndex);
    
                        if (filePath && fileName) {
                            const File = plus.android.importClass("java.io.File");
                            const file = new File(filePath);
    
                            if (file.exists()) {
                                images.value.push({
                                    name: fileName,
                                    path: 'file://' + filePath,
                                    bucket: bucketName || '未知文件夹'
                                });
                                count++;
                            }
                        }
                    } while (cursor.moveToNext());
    
                    cursor.close();
                    scanInfo.value = `通过MediaStore API找到 ${count} 张图片`;
                    console.log(`通过MediaStore API找到 ${count} 张图片`);
                }
            } catch (e) {
                console.error("加载 MediaStore 相关类失败:", e);
                uni.showToast({ title: "加载失败,请检查权限或重新打包", icon: "none" });
            }
        } catch (e) {
            console.error("权限请求失败:", e);
            uni.showToast({ title: "权限请求失败", icon: "none" });
        }
        // #endif
    };
    

    ✅ 总结

    | 问题 | 原因 | 解决方案 | |------|------|----------| | 自定义基座崩溃 | 缺少 MediaStore 类或相关依赖 | 确保在打包配置中包含所有必要类,使用 try-catch 捕获异常 | | 权限不足 | 未申请存储权限 | 在 AndroidManifest.xml 中添加权限,并动态请求 | | 模拟器重启 | 崩溃未被捕获 | 加入异常处理逻辑,避免应用直接退出 |


    如你仍无法解决,请提供:

    • manifest.json 配置片段
    • 打包时的日志或错误提示
    • 是否使用了 HBuilderXDCloud 云端打包服务

    我可以进一步帮你排查具体原因。

    评论

报告相同问题?

问题事件

  • 创建了问题 10月8日