uniapp开发App,集成极光推送,安卓和IOS,APP上架AppStore、小米、华为、荣耀、OPPO、VIVO,并且配置所有厂商离线推送
1、使用Hbuilder-选择vue2-进行App的实际开发(技术选型和开发模板自行选择)
2、app运行方式
(1)Hbuilder内置浏览器运行(Hbuilder自带功能)
(2)Hbuilder谷歌浏览器运行(Hbuilder自带功能)
(3)真机测试,需连接安卓设备或者IOS设备

备注:
(1) 真机测试,真机必须开启开发者模式,以及USB调试,不同品牌设备,打开位置不同,自行设置
(2) 真机测试一般选择使用标准基座运行,也可以使用自定义基座运行,如果使用自定义基座运行,需要通过发布选择打自定义调试基座,如果是打包功能,不管是自定义基座还是正式打包,安卓需要安卓证书和密钥,IOS也是需要描述证书和P12文件,以及证书密钥,IOS区分测试和正式,这些证书我们后面会详细说明。
(3)这真机测试必选有可选的设备,方可进行调试,如果没有设备,需要排查设备的调试功能是否打开,排查连接:[https://uniapp.dcloud.net.cn/tutorial/run/run-app-faq.html](https://uniapp.dcloud.net.cn/tutorial/run/run-app-faq.html)
3、Hbuilder开发App的基本设置

备注:1、appId,在Hbuilder新建项目时候回自动生成,不要轻易修改
2、应用名称:自己的app的名称
3、应用版本号,后面根据这个版本号,进行升级
4、Hbuilder开发App的打包(重点)
(1) 安卓打包配置
上面安卓的包名、别名、安卓证书,密钥密码,都是需要自行申请的
安卓包名生成:https://blog.csdn.net/weixin_48193914/article/details/144281822
这里面包括了搭建jdk环境,一般有后端同事的,直接找使用文章中连接,让后端同事按照你的需求生成安卓包名,别名,密码,证书,当然里面还有一些在各个手机厂商开发者平台,新建应用时候使用的参数。
(2) IOS打包配置
a、打包区分开发和正式
详细资料连接1:https://ask.dcloud.net.cn/article/152
详细资料连接2:https://blog.csdn.net/qq_39196447/article/details/136877424
b、推送P12证书生成(推送证书一般只做配置使用,后续ios 的app推送必须使用这个证书),也区分开发和正式,但是开发也可以使用正式,所以,一般只做一个试用开发和生成的就行了、详细资料连接2的最后面就有关于推送证书的获取方式,请详细阅读
4、App集成极光推送
(1) 在线配置
uniapp集成极光推送云插件,需要在极光推送网站,注册,集体方案,详见链接
https://blog.csdn.net/2301_78542842/article/details/144729012
此方案实现后,只能实现app在线消息的推送,在线消息的推送,是极光推送的,只有app在打开,并且在使用的时候能够收到消息的推送,如果app,关闭,或者进程杀掉后,就需要使用各个厂商的离线推送通道
(2) 离线推送
a、首先需要去各个厂商通道申请应用,拿到应用的必要信息
https://docs.jiguang.cn/jpush/client/Android/android_3rd_param
文章中涉及了所有厂商的主要参数的获取和账号的注册,最终这些厂商的应用信息,都需要再极光的推送设置中设置
b、各个厂商申请的应用信息,也需要再配置到Hbuilder的原生插件配置中


有些参数,是在参数前面加了前缀一定注意,我在做的时候就把前缀疏忽了,导致排查了,很久的问题,

5、App商家
(1) IOS上架,他其实相对简单,使用Hbilder,打包生产环境的包,然后使用MAC电脑,使用transpoter将ipa文件上传到appStore,然后再app developer开发者,发布,填写,需要信息,等待审核信息,如有审核不通过的,按照提示进行修改即可。
(2) 各个国内安卓厂商商家
大致的一些商家的要求,我大概罗列下
1、首次打包app,必须以弹框方式,告知用户隐私保护和服务,让用户选择(Hbuilder,提供配置,配置即可)

2、如果调用定位、拍照、文件等权限信息,需进行双告知方式,(因为vivo,必须是双告知方式,就是1、告知调用的用户,自行撰写 2、默认的手机调用权限的提示(在调用后会自行调用),这种方式,需要单独的代码逻辑实现)
上告知方式:
此处,我是state的方式实现,我把代码贴下面,涉及了其中四个权限,可以自行拓展,如果弄state,自行研究,不就行细说

permissionToast.js内容如下
const state = {
dialogView: null,
permissionListener: null,
list: [{
name: "CAMERA",
title: "相机权限申请说明:",
content: "便于您使用该功能拍摄照片进行工单处理,允许或拒绝均不会获取任何隐私信息。",
},
{
name: "READ_EXTERNAL_STORAGE",
title: "相册权限说明:",
content: "便于您使用该功能上传您的照片/图片进行工单的新建或处理,允许或拒绝均不会获取任何隐私信息。",
},
{
name: "ACCESS_FINE_LOCATION",
title: "位置权限申请说明:",
content: "便于您使用该功能方便你快速建立电站或是能够进行电站位置的路线导航,允许或拒绝均不会获取任何隐私信息。",
},
{
name: "CALL_PHONE",
title: "拨打电话权限说明:",
content: "便于您使用该功能拨打业主电话,允许或拒绝均不会获取任何隐私信息。",
}
]
}
const actions = {
//清除弹框
asyncClearDialogView({
commit
}) {
commit('clearDialogView')
},
//权限获取
//监听权限申请
async requstPermission({
state,
dispatch,
commit
}, permissionID) {
return new Promise((resolve, reject) => {
try {
console.log('🚀🚀','当前申请的权限',permissionID);
// if (!uni.getSystemInfoSync().platform == 'android') return resolve(true)
/**
* @description plus.navigator.checkPermission 检查应用是否获取指定权限
* 有些权限检测不到 就继续下面的代码,比如相册权限就可以直接检测,就很方便,授权情况下不需要再走下面代码了
* checkPermission 返回参数
* @params undetermined 未确定
* @params authorized 授权
*/
let checkPermission = plus.navigator.checkPermission('android.permission.' +
permissionID)
console.log(checkPermission);
if (checkPermission == 'authorized') return resolve(true)
//判断是否自己在list里面配置了这个权限
let index = state.list.findIndex(item => item.name == permissionID)
console.log(index, 789789789798, permissionID);
if (index == -1) throw new Error('这个权限没有配置')
//唤起原生权限说明弹框
dispatch('requstPermissionDialog', index)
//授权检测回调
plus.android.requestPermissions(
[
'android.permission.' + permissionID //单个权限
// 'android.permission.CAMERA', 'android.permission.READ_EXTERNAL_STORAGE' //多个权限
],
async (resultObj) => {
console.log(resultObj, 'resultObj');
await dispatch('asyncClearDialogView')
// 权限申请结果
/**
* @description resultObj.deniedAlways 永久拒绝授权
* 多个权限返回结果可能是{"granted":["android.permission.CAMERA"],"deniedPresent":[],"deniedAlways":["android.permission.READ_EXTERNAL_STORAGE"]}
* 这个情况就是我同时授权相册和相机,但是只允许了相机,没有授权相册
* 这个时候 可以通过deniedAlways 查看哪个权限被永久拒绝了,然后自行在设置弹框内容
* 所以可以自己判断细分一下,我下面的代码是先判断了是否有永久拒绝的权限,然后直接弹框提示用户去设置
*/
if (resultObj.deniedAlways && resultObj.deniedAlways.length > 0) {
uni.showModal({
title: '提示',
content: '操作权限已被拒绝,请手动前往设置',
confirmText: "立即设置",
success: (res) => {
if (res.confirm) {
dispatch('gotoAppPermissionSetting')
} else {
resolve(false)
}
}
})
console.log('永久拒绝授权');
} else if (resultObj.deniedPresent && resultObj.deniedPresent.length > 0) {
resolve(false)
console.log('拒绝授权');
} else
if (resultObj.granted && resultObj.granted.length > 0) {
resolve(true)
console.log('授权成功');
}
},
(error) => {
reject(false)
console.log('申请权限错误:', error);
}
);
} catch (err) {
reject(false)
console.log(err);
}
})
},
//监听弹框
requstPermissionDialog({
state,
dispatch
}, index) {
try {
let permissionListener = state.permissionListener;
console.log(index,permissionListener);
if (!permissionListener) permissionListener = uni.createRequestPermissionListener()
const dialogData = state.list[index]
permissionListener.onConfirm((res) => {
dispatch('dialogStyle', {
...dialogData,
status: true
})
})
permissionListener.onComplete(async (res) => {
permissionListener.stop()
dispatch('dialogStyle', {
title: '',
content: '',
status: false
})
})
} catch (err) {
console.log('监听弹框错误', err);
}
},
//弹框样式
dialogStyle({
state,
commit
}, data) {
console.log(data);
const {
title,
content,
status
} = data
try {
console.log('弹框样式函数',status);
if(!status) {
commit('clearDialogView')
return
}
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight;
const navigationBarHeight = systemInfo.platform === 'android' ? 48 :
44;
const totalHeight = statusBarHeight + navigationBarHeight;
commit('setDialogView', {
totalHeight,
title,
content
})
} catch (e) {
console.log(e, '权限说明弹框样式错误');
}
},
//跳转到app权限设置页面
gotoAppPermissionSetting() {
if (!uni.getSystemInfoSync().platform == 'android') {
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);
}
}
}
const mutations = {
//设置弹框
setDialogView(state, {
totalHeight,
title,
content
}) {
state.dialogView = new plus.nativeObj.View('per-modal', {
top: '0px',
left: '0px',
width: '100%',
backgroundColor: '#444',
//opacity: .5;
})
state.dialogView.drawRect({
color: '#fff',
radius: '5px'
}, {
top: totalHeight + 'px',
left: '5%',
width: '90%',
height: "100px",
})
state.dialogView.drawText(title, {
top: totalHeight + 5 + 'px',
left: "8%",
height: "30px"
}, {
align: "left",
color: "#000",
})
state.dialogView.drawText(content, {
top: totalHeight + 35 + 'px',
height: "60px",
left: "8%",
width: "84%"
}, {
whiteSpace: 'normal',
size: "14px",
align: "left",
color: "#656563"
})
state.dialogView.show()
},
//清除弹框
clearDialogView(state) {
console.log('清除弹框样式');
state.dialogView && state.dialogView.close()
state.dialogView = null
}
}
export default {
namespaced: true,
state,
actions,
mutations
};
实际调用,只有安卓会使用到,ios使用不到,可以只进行安卓处理,如果有什么不懂可以私信我
/* #ifdef APP-PLUS */
if(plus.os.name == "Android") {
if (!await THAT.requstPermission('ACCESS_FINE_LOCATION')) return
}
大致效果,别处拿来的

3、一些隐私的问题,可以找客服,自行处理,有些问题可以找极光推送的客服来处理,这块就不一一说了,基本网上可客服都会给你答案,隐私一定要详细,必须有第三方插件的说明,
我给出一个第三方的列表的内容,供大家参考
第三方信息共享清单
当你使用第三方提供的服务时,我们会在获得或确保第三方获得你的授权同意后,以及其他符合法律法规规定的情形下共享对应信息。你可以通过本清单中列举的相关信息了解第三方会如何处理你的个人信息。我们也会对第三方获取个人信息的行为进行严格约束,以保护你的个人信息安全。
为保障(你app的名字)稳定运行或实现相关功能,我们还可能会接入由第三方提供的软件开发包(SDK)实现前述目的。我们对接入的相关第三方SDK同时在以下清单中列明。你可以通过目录中提供的链接或者路径查看第三方的数据使用和保护规则。请注意,第三方SDK可能由于版本升级、策略调整等原因导致其个人信息处理类型发生变化,请以其公示的官方说明为准。
华为 HMS SDK
涉及的个人信息类型:应用基本信息、应用内设备标识符、设备的硬件信息、系统基本信息和系统设置信息
使用目的:推送消息
使用场景:在华为手机终端推送消息时使用
第三方主体:华为软件技术有限公司
数据处理方式:通过去标识化、加密传输及其他安全方式
使用场景: 在向用户推送通知或消息时使用
官网链接https://developer.huawei.com/consumer/cn/
隐私政策:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/sdk-data-security-0000001050042177
vivo 推送 SDK
涉及的个人信息类型:设备信息
使用目的:推送消息
使用场景:在 vivo 手机终端推送消息时使用
第三方主体:广东天宸网络科技有限公司及将来受让运营 vivo 开放平台的公司
数据处理方式:通过去标识化、加密传输及其他安全方式
官网链接:https://dev.vivo.com.cn/promote/pushNews
隐私政策:https://www.vivo.com.cn/about-vivo/privacy-policy
小米推送 SDK
涉及的个人信息类型:设备标识符(如 Android ID、OAID、GAID)、设备信息
使用目的:推送消息
使用场景:在小米手机终端推送消息时使用
第三方主体:北京小米移动软件有限公司
数据处理方式:通过去标识化、加密传输及其他安全方式
使用场景: 在向用户推送通知或消息时使用
官网链接:https://dev.mi.com/console/appservice/push.html
隐私政策:https://dev.mi.com/console/doc/detail?pId=1822
OPPO 推送 SDK
涉及的个人信息类型:设备标识符(如 IMEI、ICCID、IMSI、Android ID、GAID)、应用信息(如应用包名、版本号和运行状态)、网络信息(如 IP 或域名连接结果,当前网络类型)
使用目的:推送消息
使用场景:在 OPPO 手机终端推送消息时使用
第三方主体:广东欢太科技有限公司
数据处理方式:通过加密传输和处理的安全处理方式
使用场景: 在向用户推送通知或消息时使用
官网链接:https://open.oppomobile.com/new/introduction?page_name=oppopush
隐私政策:https://open.oppomobile.com/wiki/doc#id=10288
地图SDK
接收方名称: 高德软件有限公司
接收方名称: 高德软件有限公司
使用目的: 支持获取用户地理位置
共享方式: SDK本机采集
共享信息名称:地理位置(大概的位置源、精准的位置源)、WIFI 信息、正在运行的应用列表、传感器信息、网络运营商、SIM 信息、MAC 地址
使用场景: 在用户创建电站、编辑电站、导航等功能时使用
第三方个人信息处理规则:https://lbs.amap.com/pages/privacy/
极光推送SDK
第三方主体:深圳市和讯华谷信息技术有限公司
SDK 用途:为 APP 用户提供信息推送服务
收集个人信息类型: 设备参数及系统信息(设备类型、设备型号、系统版本、及相关硬件信息):用于识别用户的设备类型、设备型号、系统版本等,确保消息准确下发; 设备标识符(IMEI、IDFA、Android ID、GAID、 MAC、MAC地址、OAID、VAID、AAID、IMSI、MEID、UAID、硬件序列号信息、ICCID、SIM信息):用于识别唯一用户,保证推送的精准送达及推送信息的准确统计; 网络信息(IP 地址、WiFi 信息、基站信息、DNS地址、DHCP地址、SSID、BSSID)与位置信息(经纬度):用于优化SDK与极光服务器的网络连接请求,保证服务的稳定性和连续性,同时实现区域推送功能; 应用列表信息(软件安装列表、应用崩溃信息、通知开关状态、APP 应用列表及活跃状态、APP 应用页面信息、APP 功能事件相关信息):当一个设备有多个 APP 的推送链路同时活跃时,我们采用合并链路技术,随机合并成一条链路,以达到为用户节省电省流量的目的。
数据处理方式:通过去标识化、加密传输及其他安全方式
官网链接:https://www.jiguang.cn/push
隐私政策:https://www.jiguang.cn/license/privacy
2097

被折叠的 条评论
为什么被折叠?



