HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

关于华为应用市场上架,申请权限未告知目的被驳回问题的简单处理方式

华为应用市场

近期关于华为应用市场上架过程中出现的【您的应用在运行时,未同步告知权限申请的使用目的,向用户索取(存储、拍照)等权限,不符合华为应用市场审核标准。】

请参考《审核指南》第7.21相关审核要求:https://developer.huawei.com/consumer/cn/doc/app/50104-07#h3-1683701612940-2
(应用申请的权限,都必须有明确、合理的使用场景和功能说明,禁止诱导或误导用户授权,应用使用的权限必须与申请所述的一致。在申请敏感权限时,需同步告知用户申请该权限的目的。未经用户同意,不得更改用户权限授权状态。)

针对以上问题,个人结合现有问题贴处理方式如下,仅供参考,各位可拿去按照自己需求进行细化调整,代码如下:

使用方式:
1.引入:

import permision from "@/js_sdk/permission.js"

2.判断:

var result = await permision.premissionCheck("EXTERNAL_STORAGE")  
if(result == 1) {  
    // 此处处理各自业务 如:uni.chooseImage  
}

3.permission.js源码参考如下

var isIos  
// #ifdef APP-PLUS  
isIos = (plus.os.name == "iOS")  
// #endif  

// 判断推送权限是否开启  
function judgeIosPermissionPush() {  
    var result = false;  
    var UIApplication = plus.ios.import("UIApplication");  
    var app = UIApplication.sharedApplication();  
    var enabledTypes = 0;  
    if (app.currentUserNotificationSettings) {  
        var settings = app.currentUserNotificationSettings();  
        enabledTypes = settings.plusGetAttribute("types");  
        console.log("enabledTypes1:" + enabledTypes);  
        if (enabledTypes == 0) {  
            console.log("推送权限没有开启");  
        } else {  
            result = true;  
            console.log("已经开启推送功能!")  
        }  
        plus.ios.deleteObject(settings);  
    } else {  
        enabledTypes = app.enabledRemoteNotificationTypes();  
        if (enabledTypes == 0) {  
            console.log("推送权限没有开启!");  
        } else {  
            result = true;  
            console.log("已经开启推送功能!")  
        }  
        console.log("enabledTypes2:" + enabledTypes);  
    }  
    plus.ios.deleteObject(app);  
    plus.ios.deleteObject(UIApplication);  
    return result;  
}  

// 判断定位权限是否开启  
function judgeIosPermissionLocation() {  
    var result = false;  
    var cllocationManger = plus.ios.import("CLLocationManager");  
    var status = cllocationManger.authorizationStatus();  
    result = (status != 2)  
    console.log("定位权限开启:" + result);  
    // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation  
    /* var enable = cllocationManger.locationServicesEnabled();  
    var status = cllocationManger.authorizationStatus();  
    console.log("enable:" + enable);  
    console.log("status:" + status);  
    if (enable && status != 2) {  
        result = true;  
        console.log("手机定位服务已开启且已授予定位权限");  
    } else {  
        console.log("手机系统的定位没有打开或未给予定位权限");  
    } */  
    plus.ios.deleteObject(cllocationManger);  
    return result;  
}  

// 判断麦克风权限是否开启  
function judgeIosPermissionRecord() {  
    var result = false;  
    var avaudiosession = plus.ios.import("AVAudioSession");  
    var avaudio = avaudiosession.sharedInstance();  
    var permissionStatus = avaudio.recordPermission();  
    console.log("permissionStatus:" + permissionStatus);  
    if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {  
        console.log("麦克风权限没有开启");  
    } else {  
        result = true;  
        console.log("麦克风权限已经开启");  
    }  
    plus.ios.deleteObject(avaudiosession);  
    return result;  
}  

// 判断相机权限是否开启  
function judgeIosPermissionCamera() {  
    var result = false;  
    var AVCaptureDevice = plus.ios.import("AVCaptureDevice");  
    var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');  
    console.log("authStatus:" + authStatus);  
    if (authStatus == 3) {  
        result = true;  
        console.log("相机权限已经开启");  
    } else {  
        console.log("相机权限没有开启");  
    }  
    plus.ios.deleteObject(AVCaptureDevice);  
    return result;  
}  

// 判断相册权限是否开启  
function judgeIosPermissionPhotoLibrary() {  
    var result = false;  
    var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");  
    var authStatus = PHPhotoLibrary.authorizationStatus();  
    console.log("authStatus:" + authStatus);  
    if (authStatus == 3) {  
        result = true;  
        console.log("相册权限已经开启");  
    } else {  
        console.log("相册权限没有开启");  
    }  
    plus.ios.deleteObject(PHPhotoLibrary);  
    return result;  
}  

// 判断通讯录权限是否开启  
function judgeIosPermissionContact() {  
    var result = false;  
    var CNContactStore = plus.ios.import("CNContactStore");  
    var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);  
    if (cnAuthStatus == 3) {  
        result = true;  
        console.log("通讯录权限已经开启");  
    } else {  
        console.log("通讯录权限没有开启");  
    }  
    plus.ios.deleteObject(CNContactStore);  
    return result;  
}  

// 判断日历权限是否开启  
function judgeIosPermissionCalendar() {  
    var result = false;  
    var EKEventStore = plus.ios.import("EKEventStore");  
    var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);  
    if (ekAuthStatus == 3) {  
        result = true;  
        console.log("日历权限已经开启");  
    } else {  
        console.log("日历权限没有开启");  
    }  
    plus.ios.deleteObject(EKEventStore);  
    return result;  
}  

// 判断备忘录权限是否开启  
function judgeIosPermissionMemo() {  
    var result = false;  
    var EKEventStore = plus.ios.import("EKEventStore");  
    var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);  
    if (ekAuthStatus == 3) {  
        result = true;  
        console.log("备忘录权限已经开启");  
    } else {  
        console.log("备忘录权限没有开启");  
    }  
    plus.ios.deleteObject(EKEventStore);  
    return result;  
}  

// Android权限查询  
function requestAndroidPermission(permissionID) {  
    return new Promise((resolve, reject) => {  
        plus.android.requestPermissions(  
            permissionID.split(","),  
            // [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装  
            function(resultObj) {  
                var result = 0;  
                for (var i = 0; i < resultObj.granted.length; i++) {  
                    var grantedPermission = resultObj.granted[i];  
                    console.log('已获取的权限:' + grantedPermission);  
                    result = 1  
                }  
                for (var i = 0; i < resultObj.deniedPresent.length; i++) {  
                    var deniedPresentPermission = resultObj.deniedPresent[i];  
                    console.log('拒绝本次申请的权限:' + deniedPresentPermission);  
                    result = 0  
                }  
                for (var i = 0; i < resultObj.deniedAlways.length; i++) {  
                    var deniedAlwaysPermission = resultObj.deniedAlways[i];  
                    console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);  
                    result = -1  
                }  
                resolve(result);  
                // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限  
                // if (result != 1) {  
                // gotoAppPermissionSetting()  
                // }  
            },  
            function(error) {  
                console.log('申请权限错误:' + error.code + " = " + error.message);  
                resolve({  
                    code: error.code,  
                    message: error.message  
                });  
            }  
        );  
    });  
}  

// 使用一个方法,根据参数判断权限  
function judgeIosPermission(permissionID) {  
    if (permissionID == "location") {  
        return judgeIosPermissionLocation()  
    } else if (permissionID == "camera") {  
        return judgeIosPermissionCamera()  
    } else if (permissionID == "photoLibrary") {  
        return judgeIosPermissionPhotoLibrary()  
    } else if (permissionID == "record") {  
        return judgeIosPermissionRecord()  
    } else if (permissionID == "push") {  
        return judgeIosPermissionPush()  
    } else if (permissionID == "contact") {  
        return judgeIosPermissionContact()  
    } else if (permissionID == "calendar") {  
        return judgeIosPermissionCalendar()  
    } else if (permissionID == "memo") {  
        return judgeIosPermissionMemo()  
    }  
    return false;  
}  

// 跳转到**应用**的权限页面  
function gotoAppPermissionSetting() {  
    if (isIos) {  
        var UIApplication = plus.ios.import("UIApplication");  
        var application2 = UIApplication.sharedApplication();  
        var NSURL2 = plus.ios.import("NSURL");  
        // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");       
        var setting2 = NSURL2.URLWithString("app-settings:");  
        application2.openURL(setting2);  

        plus.ios.deleteObject(setting2);  
        plus.ios.deleteObject(NSURL2);  
        plus.ios.deleteObject(application2);  
    } else {  
        // console.log(plus.device.vendor);  
        var Intent = plus.android.importClass("android.content.Intent");  
        var Settings = plus.android.importClass("android.provider.Settings");  
        var Uri = plus.android.importClass("android.net.Uri");  
        var mainActivity = plus.android.runtimeMainActivity();  
        var intent = new Intent();  
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  
        var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);  
        intent.setData(uri);  
        mainActivity.startActivity(intent);  
    }  
}  

// 检查系统的设备服务是否开启  
// var checkSystemEnableLocation = async function () {  
function checkSystemEnableLocation() {  
    if (isIos) {  
        var result = false;  
        var cllocationManger = plus.ios.import("CLLocationManager");  
        var result = cllocationManger.locationServicesEnabled();  
        console.log("系统定位开启:" + result);  
        plus.ios.deleteObject(cllocationManger);  
        return result;  
    } else {  
        var context = plus.android.importClass("android.content.Context");  
        var locationManager = plus.android.importClass("android.location.LocationManager");  
        var main = plus.android.runtimeMainActivity();  
        var mainSvr = main.getSystemService(context.LOCATION_SERVICE);  
        var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);  
        console.log("系统定位开启:" + result);  
        return result  
    }  
}  

let permissionMap = {  
    "android": {  
        "CAMERA_EXTERNAL_STORAGE": {  
            "name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE,android.permission.CAMERA",  
            "title": "相机/相册权限说明",  
            "content": "便于您使用该功能上传您的照片/图片/视频及用于更换头像、发布产品/需求、下载、与客服沟通等场景中读取和写入相册和文件内容"  
        },  
        "CAMERA": {  
            "name": "android.permission.CAMERA",  
            "title": "相机权限说明",  
            "content": "便于您使用该功能上传图片,用于与客服沟通等场景中发送拍摄图片"  
        },  
        "EXTERNAL_STORAGE": {  
            "name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE",  
            "title": "相册权限说明",  
            "content": "便于您使用该功能上传您的照片/图片/视频及用于更换头像、发布产品/需求、下载、与客服沟通等场景中读取和写入相册和文件内容"  
        }  
    },  
    "ios": {}  
}  

let view = null;  

function showViewDesc(permission) {  
    let plat = isIos ? "ios" : "android";  
    view = new plus.nativeObj.View('per-modal', {  
        top: '0px',  
        left: '0px',  
        width: '100%',  
        backgroundColor: 'rgba(0,0,0,0.2)',  
        //opacity: '.9'     
    })  
    view.drawRect({  
        color: '#fff',  
        radius: '5px'  
    }, {  
        top: '30px',  
        left: '5%',  
        width: '90%',  
        height: "100px",  
    })  
    view.drawText(permissionMap[plat][permission]["title"], {  
        top: '40px',  
        left: "8%",  
        height: "30px"  
    }, {  
        align: "left",  
        color: "#000",  
    }, {  
        onClick: function(e) {  
            console.log(e);  
        }  
    })  
    view.drawText(permissionMap[plat][permission]["content"], {  
        top: '65px',  
        height: "60px",  
        left: "8%",  
        width: "84%"  
    }, {  
        whiteSpace: 'normal',  
        size: "14px",  
        align: "left",  
        color: "#656563"  
    })  
    view.show()  
}  

function premissionCheck(permission) {  
    return new Promise(async (resolve, reject) => {  
        let plat = isIos ? "ios" : "android";  
        if (isIos) { // ios  
            // const camera = permission.judgeIosPermission("camera");//判断ios是否给予摄像头权限  
            // //ios相册没权限,系统会自动弹出授权框  
            // //let photoLibrary = permission.judgeIosPermission("photoLibrary");//判断ios是否给予相册权限  
            // if(camera){  
            //     resolve();  
            // }else{  
            //     reject('需要开启相机使用权限');  
            // }  
            resolve(1)  
        } else { // android  
            let permission_arr = permissionMap[plat][permission]["name"].split(",");  
            let flag = true;  
            for(let i = 0;i<permission_arr.length;i++) {  
                let status = plus.navigator.checkPermission(permission_arr[i]);  
                if(status == "undetermined") {  
                    flag = false;  
                }  
            }  
            console.log("flag", flag)  
            if (flag == false) { // 未完全授权  
                showViewDesc(permission);  
                requestAndroidPermission(permissionMap[plat][permission]["name"]).then((res) => {  
                    view.close();  
                    if (res == -1) {  
                        uni.showModal({  
                            title: '提示',  
                            content: '操作权限已被拒绝,请手动前往设置',  
                            confirmText: "立即设置",  
                            success: (res) => {  
                                if (res.confirm) {  
                                    gotoAppPermissionSetting()  
                                }  
                            }  
                        })  
                    }  
                    resolve(res)  
                })  
            } else {  
                resolve(1)  
            }  
        }  
    })  
}  

module.exports = {  
    judgeIosPermission: judgeIosPermission,  
    requestAndroidPermission: requestAndroidPermission,  
    checkSystemEnableLocation: checkSystemEnableLocation,  
    gotoAppPermissionSetting: gotoAppPermissionSetting,  
    premissionCheck: premissionCheck  
}
继续阅读 »

近期关于华为应用市场上架过程中出现的【您的应用在运行时,未同步告知权限申请的使用目的,向用户索取(存储、拍照)等权限,不符合华为应用市场审核标准。】

请参考《审核指南》第7.21相关审核要求:https://developer.huawei.com/consumer/cn/doc/app/50104-07#h3-1683701612940-2
(应用申请的权限,都必须有明确、合理的使用场景和功能说明,禁止诱导或误导用户授权,应用使用的权限必须与申请所述的一致。在申请敏感权限时,需同步告知用户申请该权限的目的。未经用户同意,不得更改用户权限授权状态。)

针对以上问题,个人结合现有问题贴处理方式如下,仅供参考,各位可拿去按照自己需求进行细化调整,代码如下:

使用方式:
1.引入:

import permision from "@/js_sdk/permission.js"

2.判断:

var result = await permision.premissionCheck("EXTERNAL_STORAGE")  
if(result == 1) {  
    // 此处处理各自业务 如:uni.chooseImage  
}

3.permission.js源码参考如下

var isIos  
// #ifdef APP-PLUS  
isIos = (plus.os.name == "iOS")  
// #endif  

// 判断推送权限是否开启  
function judgeIosPermissionPush() {  
    var result = false;  
    var UIApplication = plus.ios.import("UIApplication");  
    var app = UIApplication.sharedApplication();  
    var enabledTypes = 0;  
    if (app.currentUserNotificationSettings) {  
        var settings = app.currentUserNotificationSettings();  
        enabledTypes = settings.plusGetAttribute("types");  
        console.log("enabledTypes1:" + enabledTypes);  
        if (enabledTypes == 0) {  
            console.log("推送权限没有开启");  
        } else {  
            result = true;  
            console.log("已经开启推送功能!")  
        }  
        plus.ios.deleteObject(settings);  
    } else {  
        enabledTypes = app.enabledRemoteNotificationTypes();  
        if (enabledTypes == 0) {  
            console.log("推送权限没有开启!");  
        } else {  
            result = true;  
            console.log("已经开启推送功能!")  
        }  
        console.log("enabledTypes2:" + enabledTypes);  
    }  
    plus.ios.deleteObject(app);  
    plus.ios.deleteObject(UIApplication);  
    return result;  
}  

// 判断定位权限是否开启  
function judgeIosPermissionLocation() {  
    var result = false;  
    var cllocationManger = plus.ios.import("CLLocationManager");  
    var status = cllocationManger.authorizationStatus();  
    result = (status != 2)  
    console.log("定位权限开启:" + result);  
    // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation  
    /* var enable = cllocationManger.locationServicesEnabled();  
    var status = cllocationManger.authorizationStatus();  
    console.log("enable:" + enable);  
    console.log("status:" + status);  
    if (enable && status != 2) {  
        result = true;  
        console.log("手机定位服务已开启且已授予定位权限");  
    } else {  
        console.log("手机系统的定位没有打开或未给予定位权限");  
    } */  
    plus.ios.deleteObject(cllocationManger);  
    return result;  
}  

// 判断麦克风权限是否开启  
function judgeIosPermissionRecord() {  
    var result = false;  
    var avaudiosession = plus.ios.import("AVAudioSession");  
    var avaudio = avaudiosession.sharedInstance();  
    var permissionStatus = avaudio.recordPermission();  
    console.log("permissionStatus:" + permissionStatus);  
    if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {  
        console.log("麦克风权限没有开启");  
    } else {  
        result = true;  
        console.log("麦克风权限已经开启");  
    }  
    plus.ios.deleteObject(avaudiosession);  
    return result;  
}  

// 判断相机权限是否开启  
function judgeIosPermissionCamera() {  
    var result = false;  
    var AVCaptureDevice = plus.ios.import("AVCaptureDevice");  
    var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');  
    console.log("authStatus:" + authStatus);  
    if (authStatus == 3) {  
        result = true;  
        console.log("相机权限已经开启");  
    } else {  
        console.log("相机权限没有开启");  
    }  
    plus.ios.deleteObject(AVCaptureDevice);  
    return result;  
}  

// 判断相册权限是否开启  
function judgeIosPermissionPhotoLibrary() {  
    var result = false;  
    var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");  
    var authStatus = PHPhotoLibrary.authorizationStatus();  
    console.log("authStatus:" + authStatus);  
    if (authStatus == 3) {  
        result = true;  
        console.log("相册权限已经开启");  
    } else {  
        console.log("相册权限没有开启");  
    }  
    plus.ios.deleteObject(PHPhotoLibrary);  
    return result;  
}  

// 判断通讯录权限是否开启  
function judgeIosPermissionContact() {  
    var result = false;  
    var CNContactStore = plus.ios.import("CNContactStore");  
    var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);  
    if (cnAuthStatus == 3) {  
        result = true;  
        console.log("通讯录权限已经开启");  
    } else {  
        console.log("通讯录权限没有开启");  
    }  
    plus.ios.deleteObject(CNContactStore);  
    return result;  
}  

// 判断日历权限是否开启  
function judgeIosPermissionCalendar() {  
    var result = false;  
    var EKEventStore = plus.ios.import("EKEventStore");  
    var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);  
    if (ekAuthStatus == 3) {  
        result = true;  
        console.log("日历权限已经开启");  
    } else {  
        console.log("日历权限没有开启");  
    }  
    plus.ios.deleteObject(EKEventStore);  
    return result;  
}  

// 判断备忘录权限是否开启  
function judgeIosPermissionMemo() {  
    var result = false;  
    var EKEventStore = plus.ios.import("EKEventStore");  
    var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);  
    if (ekAuthStatus == 3) {  
        result = true;  
        console.log("备忘录权限已经开启");  
    } else {  
        console.log("备忘录权限没有开启");  
    }  
    plus.ios.deleteObject(EKEventStore);  
    return result;  
}  

// Android权限查询  
function requestAndroidPermission(permissionID) {  
    return new Promise((resolve, reject) => {  
        plus.android.requestPermissions(  
            permissionID.split(","),  
            // [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装  
            function(resultObj) {  
                var result = 0;  
                for (var i = 0; i < resultObj.granted.length; i++) {  
                    var grantedPermission = resultObj.granted[i];  
                    console.log('已获取的权限:' + grantedPermission);  
                    result = 1  
                }  
                for (var i = 0; i < resultObj.deniedPresent.length; i++) {  
                    var deniedPresentPermission = resultObj.deniedPresent[i];  
                    console.log('拒绝本次申请的权限:' + deniedPresentPermission);  
                    result = 0  
                }  
                for (var i = 0; i < resultObj.deniedAlways.length; i++) {  
                    var deniedAlwaysPermission = resultObj.deniedAlways[i];  
                    console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);  
                    result = -1  
                }  
                resolve(result);  
                // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限  
                // if (result != 1) {  
                // gotoAppPermissionSetting()  
                // }  
            },  
            function(error) {  
                console.log('申请权限错误:' + error.code + " = " + error.message);  
                resolve({  
                    code: error.code,  
                    message: error.message  
                });  
            }  
        );  
    });  
}  

// 使用一个方法,根据参数判断权限  
function judgeIosPermission(permissionID) {  
    if (permissionID == "location") {  
        return judgeIosPermissionLocation()  
    } else if (permissionID == "camera") {  
        return judgeIosPermissionCamera()  
    } else if (permissionID == "photoLibrary") {  
        return judgeIosPermissionPhotoLibrary()  
    } else if (permissionID == "record") {  
        return judgeIosPermissionRecord()  
    } else if (permissionID == "push") {  
        return judgeIosPermissionPush()  
    } else if (permissionID == "contact") {  
        return judgeIosPermissionContact()  
    } else if (permissionID == "calendar") {  
        return judgeIosPermissionCalendar()  
    } else if (permissionID == "memo") {  
        return judgeIosPermissionMemo()  
    }  
    return false;  
}  

// 跳转到**应用**的权限页面  
function gotoAppPermissionSetting() {  
    if (isIos) {  
        var UIApplication = plus.ios.import("UIApplication");  
        var application2 = UIApplication.sharedApplication();  
        var NSURL2 = plus.ios.import("NSURL");  
        // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");       
        var setting2 = NSURL2.URLWithString("app-settings:");  
        application2.openURL(setting2);  

        plus.ios.deleteObject(setting2);  
        plus.ios.deleteObject(NSURL2);  
        plus.ios.deleteObject(application2);  
    } else {  
        // console.log(plus.device.vendor);  
        var Intent = plus.android.importClass("android.content.Intent");  
        var Settings = plus.android.importClass("android.provider.Settings");  
        var Uri = plus.android.importClass("android.net.Uri");  
        var mainActivity = plus.android.runtimeMainActivity();  
        var intent = new Intent();  
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  
        var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);  
        intent.setData(uri);  
        mainActivity.startActivity(intent);  
    }  
}  

// 检查系统的设备服务是否开启  
// var checkSystemEnableLocation = async function () {  
function checkSystemEnableLocation() {  
    if (isIos) {  
        var result = false;  
        var cllocationManger = plus.ios.import("CLLocationManager");  
        var result = cllocationManger.locationServicesEnabled();  
        console.log("系统定位开启:" + result);  
        plus.ios.deleteObject(cllocationManger);  
        return result;  
    } else {  
        var context = plus.android.importClass("android.content.Context");  
        var locationManager = plus.android.importClass("android.location.LocationManager");  
        var main = plus.android.runtimeMainActivity();  
        var mainSvr = main.getSystemService(context.LOCATION_SERVICE);  
        var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);  
        console.log("系统定位开启:" + result);  
        return result  
    }  
}  

let permissionMap = {  
    "android": {  
        "CAMERA_EXTERNAL_STORAGE": {  
            "name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE,android.permission.CAMERA",  
            "title": "相机/相册权限说明",  
            "content": "便于您使用该功能上传您的照片/图片/视频及用于更换头像、发布产品/需求、下载、与客服沟通等场景中读取和写入相册和文件内容"  
        },  
        "CAMERA": {  
            "name": "android.permission.CAMERA",  
            "title": "相机权限说明",  
            "content": "便于您使用该功能上传图片,用于与客服沟通等场景中发送拍摄图片"  
        },  
        "EXTERNAL_STORAGE": {  
            "name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE",  
            "title": "相册权限说明",  
            "content": "便于您使用该功能上传您的照片/图片/视频及用于更换头像、发布产品/需求、下载、与客服沟通等场景中读取和写入相册和文件内容"  
        }  
    },  
    "ios": {}  
}  

let view = null;  

function showViewDesc(permission) {  
    let plat = isIos ? "ios" : "android";  
    view = new plus.nativeObj.View('per-modal', {  
        top: '0px',  
        left: '0px',  
        width: '100%',  
        backgroundColor: 'rgba(0,0,0,0.2)',  
        //opacity: '.9'     
    })  
    view.drawRect({  
        color: '#fff',  
        radius: '5px'  
    }, {  
        top: '30px',  
        left: '5%',  
        width: '90%',  
        height: "100px",  
    })  
    view.drawText(permissionMap[plat][permission]["title"], {  
        top: '40px',  
        left: "8%",  
        height: "30px"  
    }, {  
        align: "left",  
        color: "#000",  
    }, {  
        onClick: function(e) {  
            console.log(e);  
        }  
    })  
    view.drawText(permissionMap[plat][permission]["content"], {  
        top: '65px',  
        height: "60px",  
        left: "8%",  
        width: "84%"  
    }, {  
        whiteSpace: 'normal',  
        size: "14px",  
        align: "left",  
        color: "#656563"  
    })  
    view.show()  
}  

function premissionCheck(permission) {  
    return new Promise(async (resolve, reject) => {  
        let plat = isIos ? "ios" : "android";  
        if (isIos) { // ios  
            // const camera = permission.judgeIosPermission("camera");//判断ios是否给予摄像头权限  
            // //ios相册没权限,系统会自动弹出授权框  
            // //let photoLibrary = permission.judgeIosPermission("photoLibrary");//判断ios是否给予相册权限  
            // if(camera){  
            //     resolve();  
            // }else{  
            //     reject('需要开启相机使用权限');  
            // }  
            resolve(1)  
        } else { // android  
            let permission_arr = permissionMap[plat][permission]["name"].split(",");  
            let flag = true;  
            for(let i = 0;i<permission_arr.length;i++) {  
                let status = plus.navigator.checkPermission(permission_arr[i]);  
                if(status == "undetermined") {  
                    flag = false;  
                }  
            }  
            console.log("flag", flag)  
            if (flag == false) { // 未完全授权  
                showViewDesc(permission);  
                requestAndroidPermission(permissionMap[plat][permission]["name"]).then((res) => {  
                    view.close();  
                    if (res == -1) {  
                        uni.showModal({  
                            title: '提示',  
                            content: '操作权限已被拒绝,请手动前往设置',  
                            confirmText: "立即设置",  
                            success: (res) => {  
                                if (res.confirm) {  
                                    gotoAppPermissionSetting()  
                                }  
                            }  
                        })  
                    }  
                    resolve(res)  
                })  
            } else {  
                resolve(1)  
            }  
        }  
    })  
}  

module.exports = {  
    judgeIosPermission: judgeIosPermission,  
    requestAndroidPermission: requestAndroidPermission,  
    checkSystemEnableLocation: checkSystemEnableLocation,  
    gotoAppPermissionSetting: gotoAppPermissionSetting,  
    premissionCheck: premissionCheck  
}
收起阅读 »

Uni-app 学习、交流群

uniapp

建立一个 Uni-app QQ、微信群

帮助开发者互相学习
即时解决问题
资源共享
后期的合作

QQqun:1004151935


微信群几天就过期了,可加我VX : bjawenfd 备注: 前端群 我单独拉入VX群

继续阅读 »

建立一个 Uni-app QQ、微信群

帮助开发者互相学习
即时解决问题
资源共享
后期的合作

QQqun:1004151935


微信群几天就过期了,可加我VX : bjawenfd 备注: 前端群 我单独拉入VX群

收起阅读 »

uni-app x,一个纯原生的Android App开发工具

uni_app x

uni-app x,下一代uni-app,一个神奇的产品。

用vue语法、uni的组件、api,以及uts语言,编译出了kotlin的app。不再使用js引擎和webview。纯纯的kotlin原生app。

uni-app x,让“跨平台开发性能不如原生”的这条曾广为流传的规则,扔进了历史的垃圾桶!

uni-app x原理简析

uni-app x整体推到你面前时,你可能觉得难以想象,怎么可能编译为纯原生App?uni-app过去之所以能跨平台,是因为js是跨平台的啊。

所谓,成也萧何败也萧何,而uni-app过去在app上性能不如原生,也很大程度是因为js和原生的交互通信阻塞问题。

简述下uni-app x的原理。

其实uni-app x使用的不是js,而是DCloud在2022年发布的uts语言。这是一种基于ts改造的语言,改造的目的就是让它可以全平台编译。

我们知道js和原生语言的差异性主要在于类型动态性。而ts已经为js提供了类型。uts是在ts的基础上,融合kotlinswift的特性,抽象出了一套全平台可用的编译型语言。

uts在不同平台,编译为不同的产物:

  • 在Web中编译为js
  • 在iOS中编译为swift
  • 在Android中编译为kotlin

然后DCloud又基于uts开发了uvue的ui引擎,可使用vue语法来开发界面,再补上uni的组件和api,最终形成了你目前看到的uni-app x。

让你使用熟悉的代码、跨平台的方式,却能写出和原生的功能性能完全一致的app。

而且有趣的是,我们与原生开发者交流,发现使用uni-app x开发应用,比原生开发要快非常多。

案例

很多开发者都在关注着uni-app x,等待先行者趟坑。

这几个月来,很多先行者已经发布了他们的基于uni-app x的产品。而HBuilderX也发布了里程碑的3.98正式版,已经可以支撑商业应用。

快亿商城

这是一个云端一体的、完整的电商项目。客户端、服务器,甚至还包括管理端:快亿商城管理端

t-uvue-ui

这是一个丰富的ui库,解救那些不擅长界面的开发者。当然即便是擅长界面开发的,使用这个组件库也能提升不少开发效率。

uXui

一款基于 uni-app x 的、免费、开源的 UI 框架。

快速体验

欢迎你也来体验uni-app x这个神奇的产品:用你熟悉的代码,开发出原生的Android App。

<template>  
    <view class="content">  
        <button @click="buttonClick">{{title}}</button>  
    </view>  
</template>  

<script> //注意这里编写的是uts,是ts的变种  
    export default {  
        data() {  
            return {  
                title: "Hello world"  
            }  
        },  
        onLoad() {  
            console.log('onLoad')  
        },  
        methods: {  
            buttonClick: function () {  
                uni.showModal({  
                    "showCancel": false,  
                    "content": "点了按钮"  
                })  
            }  
        }  
    }  
</script>  

<style>  
    .content {  
        width: 750rpx;  
        background-color: white;  
    }  
</style>

体验uni-app x的真实效果,在外部浏览器里下载hello uni-app x的apk,或扫描下方二维码。

hello uni-app x 演示了uni-app x目前支持的所有内置组件、API、以及诸多页面模版。

质量

uni-app x从源头重视产品质量,第一个版本就支持自动化测试。并已为uni-app x产品编写了几十个测试工程、数十万行测试例代码。

虽然这些工作导致uni-app x初期的迭代速度变慢。但让uni-app x的质量水平大幅提升。每天晚上DCloud内部众多机器在运行这些自动化测试代码,除了监控质量,还在监控启动速度、包体积大小、内存占用等各种关键指标。

插件大赛及生态

由于uts编译为kotlin,也就是kotlin在Android上能用的api、能用的三方sdk,uni-app x里都可以用。

<script>  
    import Build from 'android.os.Build';  
    export default {  
        onLoad() {  
            console.log(Build.MODEL); //调用原生对象,返回手机型号  
            console.log(uni.getSystemInfoSync().deviceModel); //调用uni API,返回手机型号。与上一行返回值相同  
        }  
    }  
</script>

上面的示例,在页面启动时打印了2行日志,显示手机型号。

  • uni.getSystemInfoSync,是uni的api
  • import的Build,是Android os的api

在uni-app x里,可以直接调用os的能力,不受限制,语法是uts的语法,但需要了解什么功能在原生里是哪个api。

使用uni.getSystemInfoSync则比较简单,看uni的文档即可,且可跨平台。

其实,uni.getSystemInfoSync 的内部实现就是一个uts模块,底层使用了一样的代码,也是import了android.os.Build。

uni.的api,大多是uts开发的,它们都开源在uni-api仓库

uni-app x作为一个原生应用,自然可以使用原生的各种sdk,包括flutter、react native、cocos、unity等原生sdk,均可集成使用。

在插件市场,有基于uni-app x的各种作品。

DCloud官方的:

三方项目:

ui库:

还有各种原生扩展的ui组件和api插件。

目前已有数百款适配uni-app x的插件。

随着插件大赛的开展,uni-app x周边生态在如火如荼的丰富中。

当然,也欢迎你来参加插件大赛,夺取丰厚的产品。插件大赛介绍详见:https://ask.dcloud.net.cn/article/40812

点击https://uniapp.dcloud.net.cn/uni-app-x/,阅读uni-app x的官方文档。

继续阅读 »

uni-app x,下一代uni-app,一个神奇的产品。

用vue语法、uni的组件、api,以及uts语言,编译出了kotlin的app。不再使用js引擎和webview。纯纯的kotlin原生app。

uni-app x,让“跨平台开发性能不如原生”的这条曾广为流传的规则,扔进了历史的垃圾桶!

uni-app x原理简析

uni-app x整体推到你面前时,你可能觉得难以想象,怎么可能编译为纯原生App?uni-app过去之所以能跨平台,是因为js是跨平台的啊。

所谓,成也萧何败也萧何,而uni-app过去在app上性能不如原生,也很大程度是因为js和原生的交互通信阻塞问题。

简述下uni-app x的原理。

其实uni-app x使用的不是js,而是DCloud在2022年发布的uts语言。这是一种基于ts改造的语言,改造的目的就是让它可以全平台编译。

我们知道js和原生语言的差异性主要在于类型动态性。而ts已经为js提供了类型。uts是在ts的基础上,融合kotlinswift的特性,抽象出了一套全平台可用的编译型语言。

uts在不同平台,编译为不同的产物:

  • 在Web中编译为js
  • 在iOS中编译为swift
  • 在Android中编译为kotlin

然后DCloud又基于uts开发了uvue的ui引擎,可使用vue语法来开发界面,再补上uni的组件和api,最终形成了你目前看到的uni-app x。

让你使用熟悉的代码、跨平台的方式,却能写出和原生的功能性能完全一致的app。

而且有趣的是,我们与原生开发者交流,发现使用uni-app x开发应用,比原生开发要快非常多。

案例

很多开发者都在关注着uni-app x,等待先行者趟坑。

这几个月来,很多先行者已经发布了他们的基于uni-app x的产品。而HBuilderX也发布了里程碑的3.98正式版,已经可以支撑商业应用。

快亿商城

这是一个云端一体的、完整的电商项目。客户端、服务器,甚至还包括管理端:快亿商城管理端

t-uvue-ui

这是一个丰富的ui库,解救那些不擅长界面的开发者。当然即便是擅长界面开发的,使用这个组件库也能提升不少开发效率。

uXui

一款基于 uni-app x 的、免费、开源的 UI 框架。

快速体验

欢迎你也来体验uni-app x这个神奇的产品:用你熟悉的代码,开发出原生的Android App。

<template>  
    <view class="content">  
        <button @click="buttonClick">{{title}}</button>  
    </view>  
</template>  

<script> //注意这里编写的是uts,是ts的变种  
    export default {  
        data() {  
            return {  
                title: "Hello world"  
            }  
        },  
        onLoad() {  
            console.log('onLoad')  
        },  
        methods: {  
            buttonClick: function () {  
                uni.showModal({  
                    "showCancel": false,  
                    "content": "点了按钮"  
                })  
            }  
        }  
    }  
</script>  

<style>  
    .content {  
        width: 750rpx;  
        background-color: white;  
    }  
</style>

体验uni-app x的真实效果,在外部浏览器里下载hello uni-app x的apk,或扫描下方二维码。

hello uni-app x 演示了uni-app x目前支持的所有内置组件、API、以及诸多页面模版。

质量

uni-app x从源头重视产品质量,第一个版本就支持自动化测试。并已为uni-app x产品编写了几十个测试工程、数十万行测试例代码。

虽然这些工作导致uni-app x初期的迭代速度变慢。但让uni-app x的质量水平大幅提升。每天晚上DCloud内部众多机器在运行这些自动化测试代码,除了监控质量,还在监控启动速度、包体积大小、内存占用等各种关键指标。

插件大赛及生态

由于uts编译为kotlin,也就是kotlin在Android上能用的api、能用的三方sdk,uni-app x里都可以用。

<script>  
    import Build from 'android.os.Build';  
    export default {  
        onLoad() {  
            console.log(Build.MODEL); //调用原生对象,返回手机型号  
            console.log(uni.getSystemInfoSync().deviceModel); //调用uni API,返回手机型号。与上一行返回值相同  
        }  
    }  
</script>

上面的示例,在页面启动时打印了2行日志,显示手机型号。

  • uni.getSystemInfoSync,是uni的api
  • import的Build,是Android os的api

在uni-app x里,可以直接调用os的能力,不受限制,语法是uts的语法,但需要了解什么功能在原生里是哪个api。

使用uni.getSystemInfoSync则比较简单,看uni的文档即可,且可跨平台。

其实,uni.getSystemInfoSync 的内部实现就是一个uts模块,底层使用了一样的代码,也是import了android.os.Build。

uni.的api,大多是uts开发的,它们都开源在uni-api仓库

uni-app x作为一个原生应用,自然可以使用原生的各种sdk,包括flutter、react native、cocos、unity等原生sdk,均可集成使用。

在插件市场,有基于uni-app x的各种作品。

DCloud官方的:

三方项目:

ui库:

还有各种原生扩展的ui组件和api插件。

目前已有数百款适配uni-app x的插件。

随着插件大赛的开展,uni-app x周边生态在如火如荼的丰富中。

当然,也欢迎你来参加插件大赛,夺取丰厚的产品。插件大赛介绍详见:https://ask.dcloud.net.cn/article/40812

点击https://uniapp.dcloud.net.cn/uni-app-x/,阅读uni-app x的官方文档。

收起阅读 »

uniapp 实现wx小程序 那种分段式半屏的文档在哪?

如视频中的 分段式弹窗、半屏路由等等关于Skyline的示例文档都没有吗?

如视频中的 分段式弹窗、半屏路由等等关于Skyline的示例文档都没有吗?

Failed to receiveTasks, instance (1) is not available. 可能原因

uniapp

uniapp热更新不会销毁旧实例导致内存里有奇奇怪怪的东西导致的,看看生命周期里有没有会导致内存泄露的东西。

uniapp热更新不会销毁旧实例导致内存里有奇奇怪怪的东西导致的,看看生命周期里有没有会导致内存泄露的东西。

uniapp关闭蓝牙还会触发uni.onBLECharacteristicValueChange回调

低功耗蓝牙
// 连接成功返回之后调佣  
onMounted(() => {  
  // 必须在这里的回调才能获取  
  uni.onBLECharacteristicValueChange(function (buffer) {  
    let int8arr = new Uint8Array(buffer.value).buffer  

  })  
})

把uni.onBLECharacteristicValueChange放进app.vue的生命周期里 保证这个方法只触发一次

继续阅读 »
// 连接成功返回之后调佣  
onMounted(() => {  
  // 必须在这里的回调才能获取  
  uni.onBLECharacteristicValueChange(function (buffer) {  
    let int8arr = new Uint8Array(buffer.value).buffer  

  })  
})

把uni.onBLECharacteristicValueChange放进app.vue的生命周期里 保证这个方法只触发一次

收起阅读 »

uniapp+vue3+vite+ts+scss实现背景星空效果

效果:


参考知乎:用CSS实现一个超美星空特效
使用到的图片

我想在微信小程序中使用,于是让ai帮我修改了一下代码:

<script setup lang="ts">  
import { ref, onMounted } from 'vue'  

interface Star {  
  left: number  
  top: number  
scale: number delay: number } const starsList = ref<Star[]>([]) onMounted(() => { const screenWidth = uni.upx2px(750) // 设备屏幕宽度对应的像素值 const screenHeight = uni.upx2px(1334) // 设备屏幕高度对应的像素值 // 初始化 starsList 数组 for (let i = 0; i < 150; i++) { const star: Star = { left: Math.random() * screenWidth, top: Math.random() * screenHeight, scale: Math.random() * 1.5, delay: Math.random() * 1.5, } starsList.value.push(star) } }) </script> <template> <view class="wrapper"> <view class="circle"></view> <view class="circle1"></view> </view> <view class="stars"> <block v-for="(star, index) in starsList" :key="index"> <view class="star" :style="{ left: star.left + 'px', top: star.top + 'px', transform: 'scale(' + star.scale + ',' + star.scale + ')', animationDelay: star.delay + 's', }" ></view> </block> </view> </template> <style scoped lang="scss"> .wrapper { position: absolute; top: 50px; left: 80%; width: 200px; height: 200px; margin-left: -100px; animation: moonline 30s linear; z-index: 1; } @keyframes moonline { 0% { top: 250px; left: 0%; opacity: 0; } 30% { top: 150px; left: 40%; opacity: 0.5; } 80% { top: 50px; left: 80%; opacity: 1; } } .circle { position: absolute; top: 0; left: 0; width: 200px; height: 200px; background-color: #efefef; box-shadow: 0 0 40px #ffffff; border-radius: 100px; animation: moonright 30s linear; } @keyframes moonright { 0% { box-shadow: 0 0 10px #ffffff; } 30% { box-shadow: 0 0 15px #ffffff; } 40% { box-shadow: 0 0 20px #ffffff; } 50% { box-shadow: 0 0 25px #ffffff; } 100% { box-shadow: 0 0 30px #ffffff; } } .stars { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #000; } .star { width: 30px; height: 30px; background: url('@/static/images/star.png') no-repeat; position: absolute; background-size: 100% 100%; animation: flash 1s alternate infinite; } @keyframes flash { 0% { opacity: 0; } 100% { opacity: 1; } } .star:hover { transform: scale(3, 3) rotate(180deg) !important; transition: all 1s; } </style>

这是一个组件,需要在主页面中使用


相关代码:

<template>  
<XingKong class="xingkong" />  
</template>  

<style lang="scss" scoped>  
.xingkong {  
  position: absolute;  
  top: 0;  
  left: 0;  
  z-index: -1;  
  width: 100%;  
  height: 100%;  
  /* 其他样式 */  
}  
</style>
继续阅读 »

效果:


参考知乎:用CSS实现一个超美星空特效
使用到的图片

我想在微信小程序中使用,于是让ai帮我修改了一下代码:

<script setup lang="ts">  
import { ref, onMounted } from 'vue'  

interface Star {  
  left: number  
  top: number  
scale: number delay: number } const starsList = ref<Star[]>([]) onMounted(() => { const screenWidth = uni.upx2px(750) // 设备屏幕宽度对应的像素值 const screenHeight = uni.upx2px(1334) // 设备屏幕高度对应的像素值 // 初始化 starsList 数组 for (let i = 0; i < 150; i++) { const star: Star = { left: Math.random() * screenWidth, top: Math.random() * screenHeight, scale: Math.random() * 1.5, delay: Math.random() * 1.5, } starsList.value.push(star) } }) </script> <template> <view class="wrapper"> <view class="circle"></view> <view class="circle1"></view> </view> <view class="stars"> <block v-for="(star, index) in starsList" :key="index"> <view class="star" :style="{ left: star.left + 'px', top: star.top + 'px', transform: 'scale(' + star.scale + ',' + star.scale + ')', animationDelay: star.delay + 's', }" ></view> </block> </view> </template> <style scoped lang="scss"> .wrapper { position: absolute; top: 50px; left: 80%; width: 200px; height: 200px; margin-left: -100px; animation: moonline 30s linear; z-index: 1; } @keyframes moonline { 0% { top: 250px; left: 0%; opacity: 0; } 30% { top: 150px; left: 40%; opacity: 0.5; } 80% { top: 50px; left: 80%; opacity: 1; } } .circle { position: absolute; top: 0; left: 0; width: 200px; height: 200px; background-color: #efefef; box-shadow: 0 0 40px #ffffff; border-radius: 100px; animation: moonright 30s linear; } @keyframes moonright { 0% { box-shadow: 0 0 10px #ffffff; } 30% { box-shadow: 0 0 15px #ffffff; } 40% { box-shadow: 0 0 20px #ffffff; } 50% { box-shadow: 0 0 25px #ffffff; } 100% { box-shadow: 0 0 30px #ffffff; } } .stars { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #000; } .star { width: 30px; height: 30px; background: url('@/static/images/star.png') no-repeat; position: absolute; background-size: 100% 100%; animation: flash 1s alternate infinite; } @keyframes flash { 0% { opacity: 0; } 100% { opacity: 1; } } .star:hover { transform: scale(3, 3) rotate(180deg) !important; transition: all 1s; } </style>

这是一个组件,需要在主页面中使用


相关代码:

<template>  
<XingKong class="xingkong" />  
</template>  

<style lang="scss" scoped>  
.xingkong {  
  position: absolute;  
  top: 0;  
  left: 0;  
  z-index: -1;  
  width: 100%;  
  height: 100%;  
  /* 其他样式 */  
}  
</style>
收起阅读 »

《安全评估报告》之如何采用uniap加固安卓app

加固

本文主要写为了获得《安全评估报告》采用uniapp加固安卓app解决问题的一些流程和其中要注意的问题,以供后来者参考。
一、缘起:
> 本app是一款题库软件,内置有笔记功能。用户会在app中写笔记。
2018年收到了魅族应用商店的通知未做理会:
尊敬的开发者:
依据《具有舆论属性或社会动员能力的互联网信息服务安全评估规定》要求,含有如下任一功能(内容)的APP,须按照APP实际办公地原则,前往全国互联网安全服务管理平台( http://www.beian.gov.cn )评估报告登录窗口提交安全评估报告。
APP内含有(一个或多个)服务或者功能:论坛、博客、微博客、聊天室、通讯群组、公众账号、短视频、网络直播、信息分享等。
请于12月25日前完成安全评估,同时发送报告截图至 dev@meizu.com 。12月25日之后,魅族应用商店将按要求处理无此报告的相关应用。
感谢您的理解与支持。
直到2023年9月份又收到了华为应用市场的通知,才不得不重视。
尊敬的开发者:
您在华为应用市场上的应用经复测核实存在以下问题,请您参考整改建议及时整改。
整改原因:
您提交的资质证明文件存在问题。不符合华为应用市场审核标准,请您在三个月内完成整改,逾期未整改应用将被下架。
­整改建议:
应用内含论坛(例:题目页面-笔记),需补充提供(1)《安全评估报告》加盖公章(2)《安全评估报告》在全国互联网安全服务管理平台的提交结果截图,且现场检查结果需为“通过”。

第二步、公安部服务管理平台办理手续:
于是,我前往公安部服务管理平台注册账号,登陆,并提交安全检测报告。
具体流程按公安部服务管理平台的要求办理
https://beian.mps.gov.cn/web/business/safeEval/create

第三步:等到网警审核。
公安部服务管理平台,会将该检测记录转交你企业所在的区网警,区网警会与你取得联系,并通知你进行安全检测。
经网友反馈,不同的地方有不同的要求,有的地方提交第三方检测评估报告即可(比如小米或腾讯的隐私检测报告),但我这里是要按要求到指定的检测机构进行检测。

第四步:检测
检测是一波三折的。
1)初测第一次检测采用的是360的免费加固,结果如下:


说明免费加固基本相当于是裸奔,这个时候我需要寻找一个可靠的加固软件。
国内加固软件有360,爱加密,梆梆,顶固,阿里和腾讯加固。
这里如果单次加固是5000左右,有低一点单次加固3500,高一点的是7500左右。
单次加固肯定是不能考虑,原因很简单,你并不能保证100%通过,如果没有通过,你就得来第二次检测。
每一次检测都是需要费用的,而且加固也不便宜。

2)复测。
这个时候我发现uniapp有加固的功能。


这里有腾讯云加固和蚂蚁云加固,我选择了蚂蚁云。
加固以后的结果如下:

说明蚂蚁云加固也有问题,后来联系uniapp的技术,技术联系阿里以后说可以修改,但是需要时间。
技术建议我用腾讯云再加固一下试试。

3)第三次检测。
这一次使用腾讯云加固。结果有一项不合格


经uniapp联系腾讯云加固,删除了这个函数,再次加固,进行第四次检测。

4)第四次检测
老实说,uniapp的技术服务很给力,及时跟进每一次的检测结果,并对检测结果进行联系对加固软件进行修改,
技术通知我加固方面已经删除了这个函数,我再次加固,成功通过,获得合格后的《安全评估报告》
下图是检测合格的安全评估报告

第五步:网警现场审核
后天再去办理这一步,希望一切顺利,以后有结果我再反馈给大家。

最后总结:
这里面每一个步骤的解决都不是顺利的,需要加固平台的技术给力才行。
因为每一个检测中心的检测标准不一定完全一致,加固平台也不一定能满足所有的检测中心。
这需要加固平台鼎力支持才可能达到。

同时,自己不能放弃,要在dcloud中搜索各种可能的解决方案。

关于费用:
目前来看,uniapp是最经济的加固方式。

感谢:
1、要感谢dcloud平台的热心用户,在这个过程中帮我解决了很多问题,特别是隐私权限方面的问题。
2、要感谢dcloud的技术热心跟进,无私无偿的帮助解决问题
3、感谢我自己的努力与坚持。

继续阅读 »

本文主要写为了获得《安全评估报告》采用uniapp加固安卓app解决问题的一些流程和其中要注意的问题,以供后来者参考。
一、缘起:
> 本app是一款题库软件,内置有笔记功能。用户会在app中写笔记。
2018年收到了魅族应用商店的通知未做理会:
尊敬的开发者:
依据《具有舆论属性或社会动员能力的互联网信息服务安全评估规定》要求,含有如下任一功能(内容)的APP,须按照APP实际办公地原则,前往全国互联网安全服务管理平台( http://www.beian.gov.cn )评估报告登录窗口提交安全评估报告。
APP内含有(一个或多个)服务或者功能:论坛、博客、微博客、聊天室、通讯群组、公众账号、短视频、网络直播、信息分享等。
请于12月25日前完成安全评估,同时发送报告截图至 dev@meizu.com 。12月25日之后,魅族应用商店将按要求处理无此报告的相关应用。
感谢您的理解与支持。
直到2023年9月份又收到了华为应用市场的通知,才不得不重视。
尊敬的开发者:
您在华为应用市场上的应用经复测核实存在以下问题,请您参考整改建议及时整改。
整改原因:
您提交的资质证明文件存在问题。不符合华为应用市场审核标准,请您在三个月内完成整改,逾期未整改应用将被下架。
­整改建议:
应用内含论坛(例:题目页面-笔记),需补充提供(1)《安全评估报告》加盖公章(2)《安全评估报告》在全国互联网安全服务管理平台的提交结果截图,且现场检查结果需为“通过”。

第二步、公安部服务管理平台办理手续:
于是,我前往公安部服务管理平台注册账号,登陆,并提交安全检测报告。
具体流程按公安部服务管理平台的要求办理
https://beian.mps.gov.cn/web/business/safeEval/create

第三步:等到网警审核。
公安部服务管理平台,会将该检测记录转交你企业所在的区网警,区网警会与你取得联系,并通知你进行安全检测。
经网友反馈,不同的地方有不同的要求,有的地方提交第三方检测评估报告即可(比如小米或腾讯的隐私检测报告),但我这里是要按要求到指定的检测机构进行检测。

第四步:检测
检测是一波三折的。
1)初测第一次检测采用的是360的免费加固,结果如下:


说明免费加固基本相当于是裸奔,这个时候我需要寻找一个可靠的加固软件。
国内加固软件有360,爱加密,梆梆,顶固,阿里和腾讯加固。
这里如果单次加固是5000左右,有低一点单次加固3500,高一点的是7500左右。
单次加固肯定是不能考虑,原因很简单,你并不能保证100%通过,如果没有通过,你就得来第二次检测。
每一次检测都是需要费用的,而且加固也不便宜。

2)复测。
这个时候我发现uniapp有加固的功能。


这里有腾讯云加固和蚂蚁云加固,我选择了蚂蚁云。
加固以后的结果如下:

说明蚂蚁云加固也有问题,后来联系uniapp的技术,技术联系阿里以后说可以修改,但是需要时间。
技术建议我用腾讯云再加固一下试试。

3)第三次检测。
这一次使用腾讯云加固。结果有一项不合格


经uniapp联系腾讯云加固,删除了这个函数,再次加固,进行第四次检测。

4)第四次检测
老实说,uniapp的技术服务很给力,及时跟进每一次的检测结果,并对检测结果进行联系对加固软件进行修改,
技术通知我加固方面已经删除了这个函数,我再次加固,成功通过,获得合格后的《安全评估报告》
下图是检测合格的安全评估报告

第五步:网警现场审核
后天再去办理这一步,希望一切顺利,以后有结果我再反馈给大家。

最后总结:
这里面每一个步骤的解决都不是顺利的,需要加固平台的技术给力才行。
因为每一个检测中心的检测标准不一定完全一致,加固平台也不一定能满足所有的检测中心。
这需要加固平台鼎力支持才可能达到。

同时,自己不能放弃,要在dcloud中搜索各种可能的解决方案。

关于费用:
目前来看,uniapp是最经济的加固方式。

感谢:
1、要感谢dcloud平台的热心用户,在这个过程中帮我解决了很多问题,特别是隐私权限方面的问题。
2、要感谢dcloud的技术热心跟进,无私无偿的帮助解决问题
3、感谢我自己的努力与坚持。

收起阅读 »

windows申请ios证书的最简方法

Apple证书

申请ios证书,苹果官方的方法是需要使用mac电脑去申请的,但是很多开发uniapp的朋友们,并没有mac电脑。

这里我分享一个在线工具,在线即可申请ios证书。

详细的使用教程如下:

https://www.yunedit.com/xueyuan/jx/ioscert017

继续阅读 »

申请ios证书,苹果官方的方法是需要使用mac电脑去申请的,但是很多开发uniapp的朋友们,并没有mac电脑。

这里我分享一个在线工具,在线即可申请ios证书。

详细的使用教程如下:

https://www.yunedit.com/xueyuan/jx/ioscert017

收起阅读 »

ios、android备案公钥、MD5等值的最简单查询方法

2023年8月后,现在上架的app都需要备案了,无论是新上架还是已上架的app都要求做备案

网上的教程要么就是要使用mac电脑去获取公钥,android则需要安装工具去获取公钥,实在是太麻烦了。

而且不同的备案平台,要求录入的公钥的格式还不一样,有的需要输入公钥16进制,有的需要输入公钥10进制。

分享一个视化工具,上传证书就可以获取app的公钥和MD5值,省去了很多时间,无需安装工具和使用mac电脑即可获取到公钥,而且这个工具的查询结果包含了各平台需要的公钥原文、公钥16进制和公钥10进制的值:

https://www.yunedit.com/androidmd5

https://www.yunedit.com/iosmd5

继续阅读 »

2023年8月后,现在上架的app都需要备案了,无论是新上架还是已上架的app都要求做备案

网上的教程要么就是要使用mac电脑去获取公钥,android则需要安装工具去获取公钥,实在是太麻烦了。

而且不同的备案平台,要求录入的公钥的格式还不一样,有的需要输入公钥16进制,有的需要输入公钥10进制。

分享一个视化工具,上传证书就可以获取app的公钥和MD5值,省去了很多时间,无需安装工具和使用mac电脑即可获取到公钥,而且这个工具的查询结果包含了各平台需要的公钥原文、公钥16进制和公钥10进制的值:

https://www.yunedit.com/androidmd5

https://www.yunedit.com/iosmd5

收起阅读 »