先介绍一下对于Android动静权限和targetSdkVersion背景:

targetSdkVersion:自2018年11月开始,GooglePlay以及国内大部分利用市场要求app编译指标SDK必须为26及以上,否则不予提交审核;有许多已有app转到APICloud开发后,因targetSdkVersion降级而导致无奈笼罩装置;2020年以来,国家网信办等监管机构也增强了对app权限合规的监管。

动静权限:Android自零碎6.0开始,提供动静权限机制,对于敏感权限(存储,定位,录音,拍照,录像等),须要在app运行过程中动静向用户申请,这就和iOS零碎的权限应用体验保持一致了(iOS始终以来就是动静权限)。

应用APICloud开发平台开发app时,如果须要获取权限,须要动静申请。因而APICloud开发平台对立了Android和iOS两个平台的动静权限操作,提供两个API:hasPermission 和 requestPermission。文档地址为:https://docs.apicloud.com/Cli...

在Android上应用动静权限,要求app编译的指标SDK(即targetSdkVersion)为23及以上(对应为android6.0及以上零碎),22及以下零碎会执行缺省解决(手机厂商也可能定制解决),APICloud为满足更广泛的开发需要,默认配置targetSdkVersion为22,即权限走零碎缺省解决。

开启动静权限,须要依照以下阐明操作:

1、新建manifest.xml文件,增加如下代码:

<?xml version="1.0" encoding="UTF-8"?><manifest>    <application name="targetSdkVersion" value="28"/></manifest>

将其中的targetSdkVersion更新为目标值,例如30;
2、将manifest.xml置于你的/我的项目代码/res/目录下(widget/res/manifest.xml);
3、将你的app代码中所有波及到须要动静权限的操作,参照示例中的代码,革新一遍(例如进行拍照录制视频等须要应用摄像头,以前的缺省解决中不须要申请摄像头权限,而开启动静权限后,必须在进行拍照之前,判断是否有摄像头权限,没有则进行申请,只有用户批准了摄像头权限能力进行接下来拍照的操作);
4、提交代码;
5、云编译界面勾选app所需的权限;
6、云编译app或自定义loader即可。

在这里须要留神的是,当你设置的targetSdkVersion大于等于23时,即意味着开启了动静权限,如果你的app带有获取IMEI、定位、录音、拍照、录像等敏感性能时,必须应用动静权限机制,先判断是否具备该性能操作权限,再进行操作,如果不具备相应的权限,对应的性能是生效的,也可能导致app解体。

为保障动静权限尽可能适配更多厂商的手机以及顺利上线Google Play,targetSdkVersion目前举荐设置为30。

以下为代码示例:

<!DOCTYPE HTML><html><head>    <meta charset="UTF-8">    <meta name="viewport"        content="maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, initial-scale=1.0, width=device-width" />    <meta name="format-detection" content="telephone=no, email=no, date=no, address=no">    <title>权限治理</title>    <link rel="stylesheet" type="text/css" href="./css/api.css" />    <link rel="stylesheet" type="text/css" href="./css/box.css" />    <script type="text/javascript" src="./script/public.js"></script>    <style>        .marg {            margin: 3px 15px;            font-size: 18px;        }    </style>    <script type="text/javascript">        apiready = function () {        }        function hasPermission(one_per) {            var perms = new Array();            if (one_per) {                perms.push(one_per);            } else {                var prs = document.getElementsByName("p_list");                for (var i = 0; i < prs.length; i++) {                    if (prs[i].checked) {                        perms.push(prs[i].value);                    }                }            }            var rets = api.hasPermission({                list: perms            });            if (!one_per) {                apialert('判断后果:' + JSON.stringify(rets));                return;            }            return rets;        }        function reqPermission(one_per, callback) {            var perms = new Array();            if (one_per) {                perms.push(one_per);            } else {                var prs = document.getElementsByName("p_list_r");                for (var i = 0; i < prs.length; i++) {                    if (prs[i].checked) {                        perms.push(prs[i].value);                    }                }            }            api.requestPermission({                list: perms,                code: 100001            }, function (ret, err) {                if (callback) {                    callback(ret);                    return;                }                var str = '申请后果:\n';                str += '申请码: ' + ret.code + '\n';                str += "是否勾选\"不再询问\"按钮: " + (ret.never ? '是' : '否') + '\n';                str += '申请后果: \n';                var list = ret.list;                for (var i in list) {                    str += list[i].name + '=' + list[i].granted + '\n';                }                apialert(str);                console.log(JSON.stringify(ret));            });        }        function opWithPermission(perm) {            if (!confirmPer(perm)) {                return;            }            if ('calendar' == perm) {                //操作日历            } else if ('camera' == perm) {                api.getPicture({                    sourceType: 'camera',                    mediaValue: 'pic',                    destinationType: 'url',                }, function (ret, err) {                    if (ret) {                        apialert(JSON.stringify(ret));                    } else {                        apialert(JSON.stringify(err));                    }                });            } else if ('contacts' == perm) {                api.openContacts({                    test: true                }, function (ret, err) {                    if (ret && ret.status) {                        apialert(JSON.stringify(ret));                    } else {                        apialert(JSON.stringify(err));                    }                });            } else if ('location' == perm) {                api.getLocation(function (ret, err) {                    if (ret && ret.status) {                        apialert(JSON.stringify(ret));                    } else {                        apialert(JSON.stringify(err));                    }                });            } else if ('microphone' == perm) {                api.startRecord({                    path: 'fs://perm-test.amr'                });            } else if ('phone' == perm) {                api.call({                    type: 'tel',                    number: '10086'                });            } else if ('sensor' == perm) {                //操作身材传感器            } else if ('sms' == perm) {                api.sms({                    numbers: ['10086'],                    text: '余额',                    silent: true                });            } else if ('storage' == perm) {                api.readFile({                    path: 'fs://test.txt'                }, function (ret, err) {                    if (ret.status) {                        console.log('readFile: ' + ret.data);                    } else {                        apialert(err.msg + ": \n" + api.fsDir);                    }                });            }        }        function confirmPer(perm) {            var has = hasPermission(perm);            if (!has || !has[0] || !has[0].granted) {                api.confirm({                    title: '揭示',                    msg: '没有取得 ' + perm + " 权限\n是否返回设置?",                    buttons: ['去设置', '勾销']                }, function (ret, err) {                    if (1 == ret.buttonIndex) {                        reqPermission(perm);                    }                });                return false;            }            return true;        }    </script></head><body>    <div>        <div id="wrap">            <div id='header'>                <div class="back" tapmode="back-aconclick="api.closeWin()">返回</div>                <h1>权限治理测试</h1>                <div class="adpt"></div>            </div>            <div class='itemtitle'>一、判断权限</div>            <div class='marg'>请抉择一个或者多个权限进行判断:</div>            <div class='marg'>日历&emsp;&emsp;&emsp;<input type="checkbox" name="p_list" value="calendar" /></div>            <div class='marg'>相机&emsp;&emsp;&emsp;<input type="checkbox" name="p_list" value="camera" /></div>            <div class='marg'>通讯录&emsp;&emsp;<input type="checkbox" name="p_list" value="contacts" /></div>            <div class='marg'>地位信息&emsp;<input type="checkbox" name="p_list" value="location" /></div>            <div class='marg'>麦克风&emsp;&emsp;<input type="checkbox" name="p_list" value="microphone" /></div>            <div class='marg'>电话&emsp;&emsp;&emsp;<input type="checkbox" name="p_list" value="phone" /></div>            <div class='marg'>身材传感器<input type="checkbox" name="p_list" value="sensor" /></div>            <div class='marg'>短信&emsp;&emsp;&emsp;<input type="checkbox" name="p_list" value="sms" /></div>            <div class='marg'>存储空间&emsp;<input type="checkbox" name="p_list" value="storage" /></div>            <div class="clickbtn" tapmode="active" onclick="hasPermission()">点击开始判断</div>            <div class='itemtitle'>二、申请权限</div>            <div class='marg'>请抉择一个或者多个权限进行申请:</div>            <div class='marg'>日历&emsp;&emsp;&emsp;<input type="checkbox" name="p_list_r" value="calendar" /></div>            <div class='marg'>相机&emsp;&emsp;&emsp;<input type="checkbox" name="p_list_r" value="camera" /></div>            <div class='marg'>通讯录&emsp;&emsp;<input type="checkbox" name="p_list_r" value="contacts" /></div>            <div class='marg'>地位信息&emsp;<input type="checkbox" name="p_list_r" value="location" /></div>            <div class='marg'>麦克风&emsp;&emsp;<input type="checkbox" name="p_list_r" value="microphone" /></div>            <div class='marg'>电话&emsp;&emsp;&emsp;<input type="checkbox" name="p_list_r" value="phone" /></div>            <div class='marg'>身材传感器<input type="checkbox" name="p_list_r" value="sensor" /></div>            <div class='marg'>短信&emsp;&emsp;&emsp;<input type="checkbox" name="p_list_r" value="sms" /></div>            <div class='marg'>存储空间&emsp;<input type="checkbox" name="p_list_r" value="storage" /></div>            <div class="clickbtn" tapmode="active" onclick="reqPermission()">点击开始申请</div>            <div class='itemtitle'>三、须要权限的API操作</div>            <div class='marg'>1、日历</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('calendar')">点击操作日历</div>            <div class='marg'>2、相机</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('camera')">点击操作照相机</div>            <div class='marg'>3、通讯录</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('contacts')">点击操作通讯录</div>            <div class='marg'>4、地位信息</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('location')">点击操作地位信息</div>            <div class='marg'>5、麦克风</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('microphone')">点击操作麦克风</div>            <div class='marg'>6、电话</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('phone')">点击操作电话</div>            <div class='marg'>7、身材传感器</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('sensor')">点击操作身材传感器</div>            <div class='marg'>8、短信</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('sms')">点击操作短信</div>            <div class='marg'>9、存储空间</div>            <div class="clickbtn" tapmode="active" onclick="opWithPermission('storage')">点击操作存储空间</div>            <br>        </div>    </div></body></html>