更新记录
1.0.4(2022-04-22)
新增: 定位接口新增开关checkPermissions控制是否检查申请定位权限,适用于在onReady,onShow内(调用会导致执行2次,检查申请权限会触发onhide,onShow)调用的需求,请自行将权限检测申请放在其他地方。
1.0.3(2022-03-09)
修复: 获取是否有权限错误
1.0.2(2021-12-30)
更新:将淘宝weex类全部更为Uniapp类。
修复:HBX3.2.16打包无回调,其余低版本未测试,建议使用最近几个版本打包。
增加:持续和单次定位接口增加apikey参数,用于不使用官方map包的应用(但其他插件需包含定位SDK)
查看更多平台兼容性
Android | Android CPU类型 | iOS |
---|---|---|
适用版本区间:4.4 - 11.0 | armeabi-v7a:未测试,arm64-v8a:未测试,x86:未测试 | × |
原生插件通用使用流程:
- 购买插件,选择该插件绑定的项目。
- 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
- 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
- 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
- 开发完毕后正式云打包
付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios
注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择
1.0.5版本增加参数控制是否检查权限,以避免在onReady,onShow生命周期调用定位接口出现执行2次。
1.0.2版本使用最近几个版本没有问题(已测HBX3.3.3-HBX3.3.5,HBX3.2.16)【HBX3.3.3及以上需要检查隐私合规,参数默认均为true,详情见底部参数表格】
与另一个基本一致,接口名称略有区别。https://ext.dcloud.net.cn/plugin?id=2018
前言
因项目特殊需要制作此插件,因个人时间有限,当前插件未做全机型测试,需要的请自行测试。
<!--测试时使用样例代码见最后面-->
目前在小米6(安卓9,夜间12:10开启早上7:31手动杀死,中间每隔一分钟上传数据到服务器,早上查看服务器共收440条数据记录在redis中)都能有很好的保活效果(只要你不主动杀死程序)。小米11Ultra[安卓11]和华为[鸿蒙]测试40分钟页无问题。
【测试过程:手机开启保活(+屏幕唤醒(10分钟),使用setInterval每分钟项服务器上传数据,数据内容为手机时间,服务端记录到redis集合中。)】
如果你的应用希望能够一直在后台运行(比如推送服务)而不被系统自动杀死的话,可以尝试一下。需要注意的是,程序保活并不代表能做到程序杀不死,除非你把你的应用做成系统应用或者加入到系统的白名单内,否则也只是提高了程序的优先级权重,减少程序被系统回收杀死的概率而已。
已知问题
1.申请忽略电池优化:在小米新机子上打开的不是优化申请窗或优化页,而是【应用智能省电】(点击是省电策略),旧机子(如MI6)没问题。但是去【设置】搜索【电池优化】当前前应用已加入。
解决方式:可以先调用省电策略,在判断是否忽略电池优化,没忽略再申请。(实际小米高版本【智能省电无限制】,好像就默认忽略电池优化了)
更新内容
v1.0.4:
新增: 定位接口新增开关checkPermissions控制是否检查申请定位权限,适用于在onReady,onShow内(调用会导致执行2次,检查申请权限会触发onhide,onShow)调用的需求,请自行将权限检测申请放在其他地方。
v1.0.3:
修复: 获取是否有权限错误
v1.0.2:
更新:将淘宝weex类全部更为Uniapp类。
修复:HBX3.2.16打包无回调,其余低版本未测试,建议使用最近几个版本打包。
增加:持续和单次定位接口增加apikey参数,用于不使用官方map包的应用(但其他插件需包含定位SDK)
v1.0.1:
!!!重要更新:同步uni官方更新,修复新版HBX(3.3.3)版本打包插件无法正常使用问题。
定位接口新增3个隐私政策参数,详细信息见底部参数表格
V1.0.0
1.新增通知类接口
2.新增悬浮窗权限检测和授权申请
3.新增获取自启动开启状态(当前仅小米可用)
4.新增打开应用设置接口
5.新增打开电源管理页接口(在不同手机展示页面不同)
使用说明
需要先添加原生插件到uniapp项目,并配置manifest.json,再代码引用。使用教程见https://ask.dcloud.net.cn/article/35412
使用本插件需先加入fun-keeplive插件,此为fun-keeplive的扩展插件,部分用户上市场可能被拒(以及不适用后台定位)特拆分为主插件和扩展插件来使用。
使用本插件需先加入fun-keeplive插件,此为fun-keeplive的扩展插件,部分用户上市场可能被拒(以及不适用后台定位)特拆分为主插件和扩展插件来使用。
使用本插件需先加入fun-keeplive插件,此为fun-keeplive的扩展插件,部分用户上市场可能被拒(以及不适用后台定位)特拆分为主插件和扩展插件来使用。
初始化
//确保工程已配置fun-keeplive和fun-keeplive-ext插件,则仅需以下代码引入调用。
const keepLive = uni.requireNativePlugin('fun-keeplive-ext');
1.测试接口
keepLive.extTest(cof, function(result) {
console.log(result)
});
2.获取是否授权定位
keepLive.hasLocationPermissions(function(result) {
console.log(result)
});
//结果code=0时,flag:true代表有定位权限,flag_br:true代表允许后台定位(AndroidQ即sdk_int>=29)
//
3.申请授权定位
keepLive.requestLocationPermissions(function(result) {
});
4.开启持续定位【参数见下方参数说明】
// notificationIdSame:true/false 默认false。是否与保活的通知ID一致,一致只显示一个,最终显示为保活的通知设置参数。
keepLive.startLocation(
{
intervalTime: 5000,
reportInterval: 5,
isReport: true,
url: 'http://192.168.0.66/fun/open/test_json.do',
params: { a: 1, B: '测试', c: true },
headers: { a: '123', B: 'abcd' },
notificationIdSame: true
},
result => {
//见下方定位返回示例
console.log('====fUN_AmapLocation定位====', JSON.stringify(result));
}
);
5.停止持续定位【参数传空对象{},保留,防后续加参数 】
keepLive.stopLocation({}, result => {
console.log('====fUN_AmapLocation定位stop====', JSON.stringify(result));
});
6.单次定位【参数见下方参数说明】
keepLive.onceLocation({}, result => {
console.log('====fUN_AmapLocation定位====', JSON.stringify(result));
}
);
7.打开GPS设置【位置信息设置】
keepLive.openGpsSetting( result => {
console.log('====fUN_AmapLocation定位====', JSON.stringify(result));
}
);
参数说明
1.持续定位接口参数:
参数 | 参数 | 参数说明 |
---|---|---|
intervalTime | 间隔时间 | 可选,设置定位间隔,单位毫秒,默认为2000ms,最低1000ms。参数类型:数字。默认值:2000 |
locationMode | 定位模式 | 可选,设置定位模式,可选的模式有高精度、仅设备、仅网络(低功耗)。默认为高精度模式。参数类型:数字。1:高精度、2:仅网络(低功耗)、3:仅设备。默认值:1 |
gpsFirst | GPS优先 | 可选,设置是否gps优先,只在高精度模式下有效。默认关闭。参数类型:布尔。true/false,默认值:false |
isReport | 是否上传 | 可选,是否使用内置客户端上传数据。参数类型:布尔。true/false,默认值:false |
reportInterval | 上传间隔 | 可选,单位:次数,时间间隔为 intervalTime*reportInterval。参数类型:数字。默认值:3 |
url | URL | 可选,上传地址。例如'http://192.168.0.66/fun/open/test_json.do' |
params | HTTP-body | 可选,其他上传数据。例如{ a: 1, B: '测试', c: true } |
headers | HTTP消息头 | 可选,HTTP消息头自定义数据。例如{ a: 1, B: '测试', c: true } |
purpose | 定位场景 | 可选,选择了对应的定位场景,SDK会根据选择的场景自行定制定位参数的值,自行设置的参数覆盖此配置。目前支持3种定位场景的设置:签到、出行、运动。默认无场景。参数类型:数字。0:无、1:签到、2:出行、3:运动。默认值:0 |
notificationTitle | 常驻通知标题 | 默认:APP名称【1.0.5新增】 |
notificationText | 常驻通知内容 | 默认:正在后台运行【1.0.5新增】 |
locationCacheEnable | 缓存机制 | 缓存机制默认启用缓存策略,SDK将在设备位置未改变时返回之前相同位置的缓存结果。当开启定位缓存功能,在高精度模式和低功耗模式下进行的网络定位结果均会生成本地缓存,不区分单次定位还是连续定位。GPS定位结果不会被缓存。参数类型:布尔,true/false,默认值:true。【1.0.9新增】 |
isContains | 隐私 | 默认值:true。是隐私权政策是否包含高德开平隐私权政策 true是包含 |
isShow | 隐私 | 默认值:true。隐私权政策是否弹窗展示告知用户 true是展示 |
isAgree | 隐私 | 默认值:true。隐私权政策是否取得用户同意 true是用户同意 |
apikey | KEY | 高德key,manifest.json文件已配置高德地图key的忽略 |
checkPermissions | 开关 | 默认值:true。控制是否检查申请定位权限,false即不检查【1.0.4新增】 |
2.单次定位接口参数:
参数 | 参数说明 | |
---|---|---|
locationMode | 定位模式 | 可选,设置定位模式,可选的模式有高精度、仅设备、仅网络(低功耗)。默认为高精度模式。参数类型:数字。1:高精度、2:仅网络(低功耗)、3:仅设备。默认值:1 |
gpsFirst | GPS优先 | 可选,设置是否gps优先,只在高精度模式下有效。默认关闭。参数类型:布尔。true/false,默认值:false |
locationCacheEnable | 缓存机制 | 缓存机制默认启用缓存策略,SDK将在设备位置未改变时返回之前相同位置的缓存结果。当开启定位缓存功能,在高精度模式和低功耗模式下进行的网络定位结果均会生成本地缓存,不区分单次定位还是连续定位。GPS定位结果不会被缓存。参数类型:布尔,true/false,默认值:true。【1.0.9新增】 |
isContains | 隐私 | 默认值:true。是隐私权政策是否包含高德开平隐私权政策 true是包含 |
isShow | 隐私 | 默认值:true。隐私权政策是否弹窗展示告知用户 true是展示 |
isAgree | 隐私 | 默认值:true。隐私权政策是否取得用户同意 true是用户同意 |
apikey | KEY | 高德key,manifest.json文件已配置高德地图key的忽略 |
checkPermissions | 开关 | 默认值:true。控制是否检查申请定位权限,false即不检查【1.0.4新增】 |
返回结果
1.关键字段code : 其值就是errorCode,2字段一样(1.1.1版本正常情况不显示,下版本增加)。0 为定位成功。错误码对照表
2.主要字段如下:
字段 | 返回值 | 返回值说明 | 备注(此处版本号为高德SDK版本号,具体使用版本取决uniapp官方集成) |
---|---|---|---|
latitude | double | 纬度 | V2.0.0版本起 |
longitude | double | 经度 | V2.0.0版本起 |
accuracy | float | 精度 | V2.0.0版本起 |
altitude | double | 海拔 | V2.0.0版本起 |
speed | float | 速度 | V2.0.0版本起 |
bearing | float | 方向角 | V2.0.0版本起 |
buildingId | String | 室内定位建筑物Id | V3.2.0版本起 |
floor | String | 室内定位楼层 | V3.2.0版本起 |
address | String | 地址描述 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
country | String | 国家 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
province | String | 省 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
sity | String | 城市 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
district | String | 城区 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
street | String | 街道 | V2.3.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
streetNum | String | 街道门牌号 | V2.3.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
cityCode | String | 城市编码 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
adCode | String | 区域编码 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
poiName | String | 当前位置POI名称 | V2.0.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
aoiName | String | 当前位置所处AOI名称 | V2.4.0版本起模式为仅设备模式(Device_Sensors)时无此信息 |
accuracyStatus | int | 设备当前 GPS 状态 | V3.1.0版本起模式为仅设备模式(Device_Sensors)时提供此信息 |
locationType | int | 定位来源 | V2.0.0版本起可参考定位类型编码表 |
locationDetail | String | 定位信息描述 | V2.0.0版本起用于问题排查 |
errorInfo | String | 定位错误信息描述 | V2.0.0版本起可参考定位错误码表 |
errorCode | String | 定位错误码 | V2.0.0版本起可参考定位错误码表 |
定位类型【locationType】对照表
响应码 | 说明 | 介绍 |
---|---|---|
0 | 定位失败 | 请通过错误码参考错误码对照表进行问题排查。 |
1 | GPS定位结果 | 通过设备GPS定位模块返回的定位结果,精度较高,在10米-100米左右 |
2 | 前次定位结果 | 网络定位请求低于1秒、或两次定位之间设备位置变化非常小时返回,设备位移通过传感器感知。 |
4 | 缓存定位结果 | 返回一段时间前设备在同样的位置缓存下来的网络定位结果 |
5 | Wifi定位结果 | 属于网络定位,定位精度相对基站定位会更好,定位精度较高,在5米-200米之间。 |
6 | 基站定位结果 | 纯粹依赖移动、联通、电信等移动网络定位,定位精度在500米-5000米之间。 |
8 | 离线定位结果 | - |
9 | 最后位置缓存 | - |
内置原生插件简要说明
内置原生插件,代码引用即可,不需要额外配置;
globalEvent
用于监听持久性事件,例如定位信息,陀螺仪等的变化。全局事件是需要额外 APIs 处理的次要 API。
modal
模块提供了以下展示消息框的 API:toast
、alert
、confirm
和 prompt
。
toast(options)
- @options
- message, string, 展示的内容.
- duration, number, 持续时间(以秒为单位)
例如:使用原生toast方便调试(在后台时也能弹,不用都接电脑方便调试)
const modal = uni.requireNativePlugin('modal');
modal.toast({
message: "====:进主页",
duration: 2
});
简单调用示例
页面按钮只是展示可以不点击,onLoad()方法已调用,打开页面,按要求授权即可测试。
如果app有推送或者手机上后台运行着厂商白名单app(如微信/QQ/邮箱等)保活效果最好。(时间长了有时假死,屏幕量一下,立马工作)
本人测试时手机除了当前插件app均无自启动权限,并且清理了内存,只剩插件app,因时间有限,测试了一小时多没问题,截止1.0.2提交时没在测试,后台看到没上传数据,只要你点亮一下屏幕(无需解锁),会继续上传。【测试手机:小米11Ultra/安卓11】
<template>
<view class="content">
<view style="margin-bottom: 100rpx;"></view>
<button @tap="startKeep ">启动服务</button>
<button @tap="gotoWhiteList">配置后台运行,白名单,自启动</button>
<button @tap="isIgnoringBattery">判断应用是否添加在白名单之中</button>
<button @tap="requestIgnoreBattery">申请电池优化</button>
<button @tap="setPowerKeeper">设置省电策略</button>
<button @tap="startToAutoStartSetting">设置自启动</button>
<button @tap="stopKeep">关闭服务</button>
<!-- <button @tap="hasLocationPermissions">获取是否授权定位</button>
<button @tap="requestLocationPermissions">申请定位</button> -->
<!-- <button @tap="topost">保活传数据</button> -->
<u-button class="m-button" type="primary" shape="circle" text="保活传数据" @click="topost"></u-button>
<view style="margin-bottom: 30rpx;"></view>
<view class="msg">{{ msg2 }}</view>
<view class="msg">
<text>{{ msg }}</text>
</view>
<!-- <view class="msg" v-html="msg"> </view> -->
</view>
</template>
<script>
// const fUN_IM = uni.requireNativePlugin('FUN-IM');
const keepLive = uni.requireNativePlugin('fun-keeplive');
const globalEvent = uni.requireNativePlugin('globalEvent');
// const fUN_AmapLocation = uni.requireNativePlugin('FUN-AmapLocation');
var _this;
export default {
data() {
return {
title: '',
msg: '',
msg2: '',
intTime: 0,
maxTime: 0,
minTime: 99999999999,
totalTime: 0,
initTime: new Date().getTime(),
lastTime: 0,
nowtime: 0,
locTime: 0,
reTime: 0,
locationType: null,
time_start: 0,
time_end: 0
};
},
onLoad() {
console.log('====:进主页');
_this = this;
const deviceId = '';
try {
deviceId = uni.getStorageSync('storage_deviceId');
if (deviceId) {
console.log(deviceId);
} else {
try {
const res = uni.getSystemInfoSync();
_this.msg2 = res.deviceId;
} catch (e) {
_this.msg2 = _this.timeFormat(null, 'mm_dd_hh_MM_ss_SSS');
}
try {
uni.setStorageSync('storage_deviceId', _this.msg2);
} catch (e) {
}
}
} catch (e) {
// error
}
if (!deviceId) {
_this.msg2 = _this.timeFormat(null, 'mm_dd_hh_MM_ss_SSS');
}
////////////////////////////////////////////直接调用这一段可以测试
_this.startKeep();
globalEvent.addEventListener('doKeepJobEvent', function() {
console.log("----doKeepJobEvent-----");
uni.request({
url: 'https://XX.XXX.com/api/open/localtion',
data: {
id: 'moyu-' + _this.msg2 + '-KJ',
loc: _this.timeFormat()
},
method: 'POST',
success: (res) => {
console.log(res)
}
})
});
_this.topost();
//////////////////////////////////////////////直接调用这一段可以测试
},
methods: {
start: function() {},
stop: function() {},
once: function() {},
timeFormat(dateTime = null, fmt = 'hh:MM:ss:SSS') {
if (!dateTime) dateTime = Number(new Date());
if (dateTime.toString().length == 10) dateTime *= 1000;
let date = new Date(Number(dateTime));
let ret;
let opt = {
'y+': date.getFullYear().toString(), // 年
'm+': (date.getMonth() + 1).toString(), // 月
'd+': date.getDate().toString(), // 日
'h+': date.getHours().toString(), // 时
'M+': date.getMinutes().toString(), // 分
's+': date.getSeconds().toString(), // 秒
'S+': date.getMilliseconds().toString() // 毫秒
};
for (let k in opt) {
ret = new RegExp('(' + k + ')').exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'));
}
}
return fmt;
},
topost() {
uni.request({
url: 'https://XX.XXX.com/api/open/localtion',
data: {
id: 'moyu-' + _this.msg2 + 'I',
loc: _this.timeFormat()
},
method: 'POST',
success: (res) => {
console.log(res)
}
});
let dst = setInterval(function() {
uni.request({
url: 'https://XX.XXX.com/api/open/localtion',
data: {
id: 'moyu-' + _this.msg2 + 'I',
loc: _this.timeFormat()
},
method: 'POST',
success: (res) => {
console.log(res)
}
});
}, 1000 * 60)
},
startKeep() {
let cof = {
mode: 1, //0省电模式 1流氓模式
title: "推送服务", //通知栏标题
text: "正在运行,请勿关闭", //通知栏内容
isShow: true //通知栏显示 true显示,false隐藏(建议true)
}
keepLive.startKeep(cof, function(result) {
console.log(result)
});
keepLive.isIgnoringBatteryOptimizations(function(res) {
console.log(res);
let flag = res.flag;
if (flag == false) {
keepLive.gotoWhiteList()
}
})
keepLive.openWakeLock({
time: 1
}, function(result) {
console.log(result)
});
},
//判断应用是否添加在白名单之中
isIgnoringBattery() {
keepLive.isIgnoringBatteryOptimizations(function(result) {
console.log(result)
})
},
//申请加入白名单
requestIgnoreBattery() {
keepLive.requestIgnoreBatteryOptimizations(function(result) {
console.log(result)
});
},
setPowerKeeper() {
keepLive.setPowerKeeper(function(result) {
console.log(result)
});
},
//设置app自启动
startToAutoStartSetting() {
keepLive.startToAutoStartSetting();
},
stopKeep() {
keepLive.stopKeep(function(result) {
console.log(result)
});
},
hasLocationPermissions() {
keepLive.hasLocationPermissions(function(result) {
console.log(result)
});
},
requestLocationPermissions() {
keepLive.requestLocationPermissions();
},
gotoWhiteList() {
keepLive.gotoWhiteList()
},
}
};
</script>
<style>
.content {
margin: 15rpx;
}
.m-button {
margin: 15rpx 0;
}
.msg {
width: 750rpx;
}
</style>