
uni-push开通指南
> 文档已迁移至新链接:https://uniapp.dcloud.net.cn/uni-push/open.html
> 如有疑问,可以单独发贴咨询。
> 文档已迁移至新链接:https://uniapp.dcloud.net.cn/uni-push/open.html
> 如有疑问,可以单独发贴咨询。

uni-app/mui/小程序 可用的 RSA/SHA/MD5 签名/加密 SDK
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
收起阅读 »
自已写的一个原生底部选项卡的封装
现有的5 app中官方的原生底部tabbar选项卡例子简直反人类,分布在配置文件,util.js,index.html三个文件里面,而且还不会自动判断,稍微改点东西就出错,气到七窍生烟。一怒之下自己写了一个封装,用起来还不错,希望能帮到像我一样的人。
html中的使用方法:
var tabBarSet = {
activeIndex: 0,//载入时激活的选项
textSize: "12px",
fontSrc: "_www/fonts/mui.ttf",
color: "#ccc",
colorActive: "#f60",
items: [{
icon: "\ue262",
iconSize: "26px",
text: "首页",
click: function() {
mess.innerHTML = "点击了首页";
console.log("点击了首页");
}
},
{
icon: "\ue464",
iconSize: "26px",
text: "上传",
click: function() {
mess.innerHTML = "点击了上传";
console.log("点击了上传");
}
},
{
icon: "\ue502",
iconSize: "26px",
text: "设置",
click: function() {
var theurl = $.json("server") === null ? server : $.json("server");
mui.prompt("请输入服务器地址(需加https://)", theurl, "修改服务器ip地址", function(e) {
if (e.index === 1) {
$.json("server", e.value);
server = e.value;
mui.toast("服务器地址已修改为" e.value);
}
}, "div");
document.querySelector('.mui-popup-input input').value = theurl;
}
}
]
};
mui.plusReady(function() {
hh_tabbar(tabBarSet)
});
tabbar.js =>
(function() {
var xview = plus.nativeObj.View.getViewById("hhtabBar");
if (xview != null) {
xview.close();
}
var nview = null;
var nviewtags = [];
nview = new plus.nativeObj.View("hhtabBar");
window.hh_tabbarClear = function() {
nview.reset();
}
window.hh_tabbar = function(tabBarSet) {
var persent = 100 / (tabBarSet.items.length);
nview.setStyle({
left: "0px",
bottom: "0px",
width: "100%",
height: "60px"
});
nviewtags = [];
var currLeft = 0;
for (var i = 0; i < tabBarSet.items.length; i++) {
var tjson = tabBarSet.items[i];
nviewtags.push({
tag: "font",
id: "bar" + i,
text: tjson.icon,
position: {
top: "5px",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
fontSrc: tabBarSet.fontSrc,
align: 'center',
color: tabBarSet.color,
size: tjson.iconSize
}
});
nviewtags.push({
tag: "font",
id: "barText" + i,
text: tjson.text,
position: {
top: "50%",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
align: 'center',
color: tabBarSet.color,
size: tabBarSet.textSize
}
});
currLeft += persent;
}
//画最上面的那条线
nviewtags.push({
tag: 'rect',
id: 'BorderTop',
position: {
top: '0px',
left: '0px',
width: '100%',
height: '1px'
},
rectStyles: {
color: '#ccc'
}
});
nview.draw(nviewtags);
var myself = plus.webview.currentWebview();
myself.append(nview);
var pageW = window.innerWidth;
nview.addEventListener("click", function(e) {
var clientX = e.clientX;
var currIndex = 0;
var widthBlock = pageW / tabBarSet.items.length;
for (var i = 0; i < tabBarSet.items.length; i++) {
if (e.clientX > i * widthBlock && e.clientX < (i + 1) * widthBlock) {
currIndex = i;
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
tabBarSet.items[currIndex].click.apply(nview, [e]);
});
for (var i = 0; i < tabBarSet.items.length; i++) {
if (tabBarSet.activeIndex === i) {
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
};
var tabbarUpdate = function(TheIndex, TheColor) {
var thetag = nviewtags[TheIndex * 2];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "bar" + TheIndex);
thetag = nviewtags[TheIndex * 2 + 1];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "barText" + TheIndex);
}
})();
现有的5 app中官方的原生底部tabbar选项卡例子简直反人类,分布在配置文件,util.js,index.html三个文件里面,而且还不会自动判断,稍微改点东西就出错,气到七窍生烟。一怒之下自己写了一个封装,用起来还不错,希望能帮到像我一样的人。
html中的使用方法:
var tabBarSet = {
activeIndex: 0,//载入时激活的选项
textSize: "12px",
fontSrc: "_www/fonts/mui.ttf",
color: "#ccc",
colorActive: "#f60",
items: [{
icon: "\ue262",
iconSize: "26px",
text: "首页",
click: function() {
mess.innerHTML = "点击了首页";
console.log("点击了首页");
}
},
{
icon: "\ue464",
iconSize: "26px",
text: "上传",
click: function() {
mess.innerHTML = "点击了上传";
console.log("点击了上传");
}
},
{
icon: "\ue502",
iconSize: "26px",
text: "设置",
click: function() {
var theurl = $.json("server") === null ? server : $.json("server");
mui.prompt("请输入服务器地址(需加https://)", theurl, "修改服务器ip地址", function(e) {
if (e.index === 1) {
$.json("server", e.value);
server = e.value;
mui.toast("服务器地址已修改为" e.value);
}
}, "div");
document.querySelector('.mui-popup-input input').value = theurl;
}
}
]
};
mui.plusReady(function() {
hh_tabbar(tabBarSet)
});
tabbar.js =>
(function() {
var xview = plus.nativeObj.View.getViewById("hhtabBar");
if (xview != null) {
xview.close();
}
var nview = null;
var nviewtags = [];
nview = new plus.nativeObj.View("hhtabBar");
window.hh_tabbarClear = function() {
nview.reset();
}
window.hh_tabbar = function(tabBarSet) {
var persent = 100 / (tabBarSet.items.length);
nview.setStyle({
left: "0px",
bottom: "0px",
width: "100%",
height: "60px"
});
nviewtags = [];
var currLeft = 0;
for (var i = 0; i < tabBarSet.items.length; i++) {
var tjson = tabBarSet.items[i];
nviewtags.push({
tag: "font",
id: "bar" + i,
text: tjson.icon,
position: {
top: "5px",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
fontSrc: tabBarSet.fontSrc,
align: 'center',
color: tabBarSet.color,
size: tjson.iconSize
}
});
nviewtags.push({
tag: "font",
id: "barText" + i,
text: tjson.text,
position: {
top: "50%",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
align: 'center',
color: tabBarSet.color,
size: tabBarSet.textSize
}
});
currLeft += persent;
}
//画最上面的那条线
nviewtags.push({
tag: 'rect',
id: 'BorderTop',
position: {
top: '0px',
left: '0px',
width: '100%',
height: '1px'
},
rectStyles: {
color: '#ccc'
}
});
nview.draw(nviewtags);
var myself = plus.webview.currentWebview();
myself.append(nview);
var pageW = window.innerWidth;
nview.addEventListener("click", function(e) {
var clientX = e.clientX;
var currIndex = 0;
var widthBlock = pageW / tabBarSet.items.length;
for (var i = 0; i < tabBarSet.items.length; i++) {
if (e.clientX > i * widthBlock && e.clientX < (i + 1) * widthBlock) {
currIndex = i;
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
tabBarSet.items[currIndex].click.apply(nview, [e]);
});
for (var i = 0; i < tabBarSet.items.length; i++) {
if (tabBarSet.activeIndex === i) {
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
};
var tabbarUpdate = function(TheIndex, TheColor) {
var thetag = nviewtags[TheIndex * 2];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "bar" + TheIndex);
thetag = nviewtags[TheIndex * 2 + 1];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "barText" + TheIndex);
}
})();
收起阅读 »

uni-app/mui/小程序 可用的 RSA/SHA/MD5 签名/加密 SDK
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
收起阅读 »
uni-app项目展示屏幕文字滚动效果
插件预览图

使用教程
1.插件代码拷贝
- 下载后把components目录下screenTextScroll.vue文件拷贝到自己项目目录下
2.插件全局配置
- 在项目里main.js中配置如下代码
import screenTextScroll from './components/screenTextScroll.vue'
Vue.component('textscroll',screenTextScroll)
3.插件使用
- vue页面使用
<template>
<view class="content">
<textscroll :list="list"/>
</view>
</template>
<script>
export default {
data() {
return {
list:['1分钟前,无夏购买了会员','2分钟前,无夏购买了会员','3分钟前,无夏购买了会员']
};
},
onLoad() {},
methods: {
}
};
</script>
<style>
</style>
兼容性
uni-app项目中使用都兼容
插件预览图
使用教程
1.插件代码拷贝
- 下载后把components目录下screenTextScroll.vue文件拷贝到自己项目目录下
2.插件全局配置
- 在项目里main.js中配置如下代码
import screenTextScroll from './components/screenTextScroll.vue'
Vue.component('textscroll',screenTextScroll)
3.插件使用
- vue页面使用
<template>
<view class="content">
<textscroll :list="list"/>
</view>
</template>
<script>
export default {
data() {
return {
list:['1分钟前,无夏购买了会员','2分钟前,无夏购买了会员','3分钟前,无夏购买了会员']
};
},
onLoad() {},
methods: {
}
};
</script>
<style>
</style>
兼容性
uni-app项目中使用都兼容
收起阅读 »
【疑难杂症】HBuilder 打包后百度/高德原生地图不可用的解决办法
【问题描述】
使用 plus.maps 创建原生百度/高德地图,在真机调试的时候地图显示正常,打包(apk)后地图无法显示。
【问题截图】
【问题原因】
因为 HBuilder 已经不怎么维护,官网推荐使用 HBuilderX,并且推测这两个开发工具的云端打包不是使用的一套系统,
随着 HBuilder 的停止维护对应的云端打包系统也停止了维护,所以产生了此问题。
【解决方案】
下载最新版 HBuilderX 打开项目,直接提交云端打包即可。
【效果展示】
使用 plus.maps 相关接口创建的原生(百度)地图
【问题描述】
使用 plus.maps 创建原生百度/高德地图,在真机调试的时候地图显示正常,打包(apk)后地图无法显示。
【问题截图】
【问题原因】
因为 HBuilder 已经不怎么维护,官网推荐使用 HBuilderX,并且推测这两个开发工具的云端打包不是使用的一套系统,
随着 HBuilder 的停止维护对应的云端打包系统也停止了维护,所以产生了此问题。
【解决方案】
下载最新版 HBuilderX 打开项目,直接提交云端打包即可。
【效果展示】
使用 plus.maps 相关接口创建的原生(百度)地图

解决页面被输入框顶起不回弹的问题!
如果输入框在页面中比较低。 激活输入框后, 页面会被顶起, 并且不会自动回来。
如果关闭了页面拉动。 那顶起后用手滑都回不来。 很郁闷。
解决方案:
在输入框加入 @blur="blur_input"
<input type="number" name="pn" @blur="blur_input" v-model="phoneno" maxlength="11"></input>
方法:
blur_input:function() {
uni.pageScrollTo({
scrollTop:0,
})
},
更多uni.pageScrollTo的使用方法。请查看文档。
如果输入框在页面中比较低。 激活输入框后, 页面会被顶起, 并且不会自动回来。
如果关闭了页面拉动。 那顶起后用手滑都回不来。 很郁闷。
解决方案:
在输入框加入 @blur="blur_input"
<input type="number" name="pn" @blur="blur_input" v-model="phoneno" maxlength="11"></input>
方法:
blur_input:function() {
uni.pageScrollTo({
scrollTop:0,
})
},
更多uni.pageScrollTo的使用方法。请查看文档。
收起阅读 »
去设置里打开相机权限
function openCamera(){
var msg = "请在应用权限里设置允许使用相机权限";
mui.alert(msg,"开启相机权限","去开启",function(){
if (mui.os.ios) {
plus.runtime.openURL("app-settings:CAMERA");
} else {
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var Build = plus.android.importClass("android.os.Build");
var Uri = plus.android.importClass("android.net.Uri");
var intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {//系统8.0以上的
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", main.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {//系统8.0以下的
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());
}
main.startActivity(intent);
//
}
})
};
function openCamera(){
var msg = "请在应用权限里设置允许使用相机权限";
mui.alert(msg,"开启相机权限","去开启",function(){
if (mui.os.ios) {
plus.runtime.openURL("app-settings:CAMERA");
} else {
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var Build = plus.android.importClass("android.os.Build");
var Uri = plus.android.importClass("android.net.Uri");
var intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {//系统8.0以上的
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", main.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {//系统8.0以下的
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());
}
main.startActivity(intent);
//
}
})
};
收起阅读 »

个推平台消息推送踩坑经验分享
以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。
(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同
1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。
2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。
3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。
(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。
1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。
2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。
- 踩坑总结如下:
- 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
- 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
- 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
- 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
- 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
- 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
*/
一、以下是watcher.js实现逻辑
if(window.plus) {
newsClick();
} else {
document.addEventListener('plusready', newsClick, false);
}
function newsClick() {
//获取个推 CID
//mui.toast(plus.push.getClientInfo().clientid);
// 监听plusready事件
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name=='iOS') {//ios当前应用离线时
if(msg.aps){
pushGetRun(msg.payload);
}
}else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件
if(msg.payload){
var payload = eval('(' + msg.payload + ')');
pushGetRun(payload);
}
}
}, false);
plus.push.addEventListener("receive", function(msg) {
//获取透传数据,统一将回调对象msg处理成json对象
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调
if(msg.payload){
if(typeof(msg.payload) == "string"){
// mui.alert("payload(String): " + msg.payload);
//字符串处理
var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`
if(payloadJson.payload){
newsConfirm(payloadJson.payload);//弹出新消息层
}
}else if(typeof(msg.payload) == "object"){
if(msg.payload.payload){
var payloadObj = null;
if(typeof(msg.payload.payload) == 'string'){
payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object
}else if(typeof(msg.payload.payload) == "object"){
payloadObj = msg.payload.payload;
}
if(payloadObj){
newsConfirm(payloadObj);//弹出新消息层
}else{//异常处理
// clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
}
}
}else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调
if(msg.payload){
newsConfirm(msg.payload);//弹出新消息层
}else{//异常处理
}
//创建本地消息
// plus.push.createMessage(msg.content, msg.payload, {
// title: msg.title,
// cover: false
// });
}
}, false);
function pushGetRun(payload) {//用参数打开指定页面
//eval()函数将字符串转换时需要区分是否是ios
var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');
if(data.url&&data.hasOwnProperty("params")){
clicked(data.url, data.params);
}else{//异常处理
mui.toast("参数缺失或错误");
clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
//程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件
document.addEventListener("newintent", openWebviewFromOthers, false);
//获取通知栏(app未启动)点击、第三方程序启动本app
function openWebviewFromOthers() {
var args = plus.runtime.arguments;
if(args.indexOf('wechat') < 0 && args) {
// mui.toast("----args----" +JSON.stringify(args));
pushGetRun(args);
}
}
function newsConfirm(payload){
plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {
if(e.index == 0) {
pushGetRun(payload);
}
}, "新消息通知", ["查看", "忽略"]);
}
};
/*
* 针对ios不能执行eval("(" + str ")")来强制转化成json对象,
* 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;
* 以下为调用例子:
* var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;
* toJSON(toJSONStr2(toJSONStr1(a)));//测试
*/
function toJSONStr1(str){
//全局将字符串 '{ 和 }' 替换成 { 和 } ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)
return str.replace(/'{/g,"{").replace(/}'/g, "}");
}
function toJSONStr2(str) { //全局将属性名添加上双引号 ""
return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});
}
function toJSON(str) { //处理标准格式的字符串成json对象
return JSON.parse(str);
}
二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:
//消息事件监听
var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");
if(!watcherObj){//不存在才创建
var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");
//创建完隐藏
watcher.hide();
}
四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:
{
title: "通知标题",
content: "通知内容",
payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'
}
IOS参数设置----payload的自定义值参考如下:
{
"url": "_www/view/discovery/discoverydetail.html",
"params": {
"article_id": 51
}
}
五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)
六、以下附件是个推平台上要注意的事项截图;
以上全部,欢迎大家一起讨论!
以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。
(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同
1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。
2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。
3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。
(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。
1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。
2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。
- 踩坑总结如下:
- 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
- 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
- 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
- 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
- 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
- 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
*/
一、以下是watcher.js实现逻辑
if(window.plus) {
newsClick();
} else {
document.addEventListener('plusready', newsClick, false);
}
function newsClick() {
//获取个推 CID
//mui.toast(plus.push.getClientInfo().clientid);
// 监听plusready事件
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name=='iOS') {//ios当前应用离线时
if(msg.aps){
pushGetRun(msg.payload);
}
}else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件
if(msg.payload){
var payload = eval('(' + msg.payload + ')');
pushGetRun(payload);
}
}
}, false);
plus.push.addEventListener("receive", function(msg) {
//获取透传数据,统一将回调对象msg处理成json对象
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调
if(msg.payload){
if(typeof(msg.payload) == "string"){
// mui.alert("payload(String): " + msg.payload);
//字符串处理
var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`
if(payloadJson.payload){
newsConfirm(payloadJson.payload);//弹出新消息层
}
}else if(typeof(msg.payload) == "object"){
if(msg.payload.payload){
var payloadObj = null;
if(typeof(msg.payload.payload) == 'string'){
payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object
}else if(typeof(msg.payload.payload) == "object"){
payloadObj = msg.payload.payload;
}
if(payloadObj){
newsConfirm(payloadObj);//弹出新消息层
}else{//异常处理
// clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
}
}
}else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调
if(msg.payload){
newsConfirm(msg.payload);//弹出新消息层
}else{//异常处理
}
//创建本地消息
// plus.push.createMessage(msg.content, msg.payload, {
// title: msg.title,
// cover: false
// });
}
}, false);
function pushGetRun(payload) {//用参数打开指定页面
//eval()函数将字符串转换时需要区分是否是ios
var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');
if(data.url&&data.hasOwnProperty("params")){
clicked(data.url, data.params);
}else{//异常处理
mui.toast("参数缺失或错误");
clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
//程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件
document.addEventListener("newintent", openWebviewFromOthers, false);
//获取通知栏(app未启动)点击、第三方程序启动本app
function openWebviewFromOthers() {
var args = plus.runtime.arguments;
if(args.indexOf('wechat') < 0 && args) {
// mui.toast("----args----" +JSON.stringify(args));
pushGetRun(args);
}
}
function newsConfirm(payload){
plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {
if(e.index == 0) {
pushGetRun(payload);
}
}, "新消息通知", ["查看", "忽略"]);
}
};
/*
* 针对ios不能执行eval("(" + str ")")来强制转化成json对象,
* 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;
* 以下为调用例子:
* var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;
* toJSON(toJSONStr2(toJSONStr1(a)));//测试
*/
function toJSONStr1(str){
//全局将字符串 '{ 和 }' 替换成 { 和 } ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)
return str.replace(/'{/g,"{").replace(/}'/g, "}");
}
function toJSONStr2(str) { //全局将属性名添加上双引号 ""
return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});
}
function toJSON(str) { //处理标准格式的字符串成json对象
return JSON.parse(str);
}
二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:
//消息事件监听
var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");
if(!watcherObj){//不存在才创建
var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");
//创建完隐藏
watcher.hide();
}
四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:
{
title: "通知标题",
content: "通知内容",
payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'
}
IOS参数设置----payload的自定义值参考如下:
{
"url": "_www/view/discovery/discoverydetail.html",
"params": {
"article_id": 51
}
}
五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)
六、以下附件是个推平台上要注意的事项截图;
以上全部,欢迎大家一起讨论!
收起阅读 »
希望uni-app打包成app的时候能够把webview内核打包进去
在一些手机上经常会遇到,因为手机自带webview内核过低,导致页面上的一些问题,希望uni-app能自己打包上,调用自己的。
在一些手机上经常会遇到,因为手机自带webview内核过低,导致页面上的一些问题,希望uni-app能自己打包上,调用自己的。

uni-app中在同一个页面使用多个picker组件出现的一些问题以及解决方法
作为一个刚刚了解一点微信小程序就被迫改用uni-app的人来说,这个框架给我的感觉就是哪里都是坑。倒不是说框架本身问题很多,而是自己没有太多的参考对象。当初学微信的时候,遇到一点问题上百度搜真的是一搜一大把,而现在就是屈指可数。而且也没有什么教学视频,至少我当初入坑时,能搜到的视频还是要收费的。总之这一路走得不平坦,但也感觉收获了不少。现在依然有很多问题,但是学会了用微信小程序来转化成uni-app,很多时候思路都是一样的,至少具体写法有些不同。这也会让我很抓狂,毕竟,我真的是个新手,很多基础知识都不熟,文档也是看得头痛还不能理解。
这不,刚刚就把一个困扰了许久的问题解决了,思路正是来自微信小程序的。这是思路来源,感谢!https://segmentfault.com/a/1190000009797083
<block v-for="(student,index) in studentlist2" :key="index">
<view class="student-list-item padding-sm">
<image class="avatar" :src="student.avatar">
</image>
<view class="student-info padding-sm">
<view class="name font-md">{{student.name}}<span class="iconfont icon-yezi"></span></view>
<view class="student-id font-sm grey main-font-color">{{student.id}}</view>
</view>
<picker @change="bindPickerChange" :value="student.newindex" :range="array" :data-current="index">
<view class="uni-input">{{array[student.newindex]}}</view>
</picker>
</view>
<view class="border"></view>
</block>
这是视图层,用到是for循环实现一个学生列表。对没有及时签到的学生可以进行选择,故需要用到picker。可是问题就来了,有多个picker,里面的{{array[index]}}显示的内容都是由data中的同一个index控制的,这样,每一次改变其中一个picker的值时,所有的picker都会改变值。这个问题困扰了我许久。当时我就想如果可以得到当前改变的picker的index就好了,这样就可以指定改变的picker了。但是当时的我不知道如何获取。
我的疑点有以下几点:
1.如何获取当前的index?本来也是可以的,用一个函数,参数为student,然后在函数里写index=e.index不就好了?可是这里绑定的函数是@change="bindPickerChange",和普通的绑定不一样,我不知道如何传参。
- 然后就是我不知到为何在method中的bindPickerChange又是有一个参数e的。我知道是自己基础不好,对e的认识很浅。我试图用console.log来获取e,看看其内部究竟有哪些值,但结果并不好。
- 能不能用data-XXX呢?其实如果是在微信小程序里面,我肯定首选这个,但是在uni-app里,我一直以为不能用data-XXX,因为官方文档似乎没有,网上也没有找到(我的搜索水平太差了),或者说这是默认就可以的。总之,我直到看了搭档这样用以后才知道原来uni-app是可以用的。当时我还很惊讶地问他是怎么知道的,他说还是当初学小程序的时候我教他的。卧槽,这么interesting的吗?
今天终于在一篇解决微信小程序的文章里找到了思路,也解决了之前的疑点。
其实以上三点都是一样的。因为data-xxx是可以用的,而在e里面就是可以看到data-xxx的,这就是答案。
studentlist2: [
{
newindex:0,
avatar: '/static/lishi.jpg',
name: '楚秋然',
id: '2017082314'
},
{
newindex:1,
avatar: '/static/xinli.jpg',
name: '愧泽',
id: '2017082315'
}
]
bindPickerChange: function(e) {
const curindex = e.target.dataset.current
console.log('picker发送选择改变,携带值为', e.target.value)
console.log('picker发送选择改变,携带值为', curindex)
this.studentlist2[curindex].newindex = e.target.value
console.log("index="+this.studentlist.index)
}
感觉自己是基础太差了。又没有人带,不然,这么easy的问题真的不该被卡住这么久。一个小白之所以会不自量力地写一篇文章也是想积累一些经验,和大家交流一下。而且,这个问题似乎都没有人写过,想着可能是太简单了没有必要写。但是如果有像我一样的小白,希望能对你有帮助。毕竟,当初的我是多么渴望有这么一篇文章来帮助我。
作为一个刚刚了解一点微信小程序就被迫改用uni-app的人来说,这个框架给我的感觉就是哪里都是坑。倒不是说框架本身问题很多,而是自己没有太多的参考对象。当初学微信的时候,遇到一点问题上百度搜真的是一搜一大把,而现在就是屈指可数。而且也没有什么教学视频,至少我当初入坑时,能搜到的视频还是要收费的。总之这一路走得不平坦,但也感觉收获了不少。现在依然有很多问题,但是学会了用微信小程序来转化成uni-app,很多时候思路都是一样的,至少具体写法有些不同。这也会让我很抓狂,毕竟,我真的是个新手,很多基础知识都不熟,文档也是看得头痛还不能理解。
这不,刚刚就把一个困扰了许久的问题解决了,思路正是来自微信小程序的。这是思路来源,感谢!https://segmentfault.com/a/1190000009797083
<block v-for="(student,index) in studentlist2" :key="index">
<view class="student-list-item padding-sm">
<image class="avatar" :src="student.avatar">
</image>
<view class="student-info padding-sm">
<view class="name font-md">{{student.name}}<span class="iconfont icon-yezi"></span></view>
<view class="student-id font-sm grey main-font-color">{{student.id}}</view>
</view>
<picker @change="bindPickerChange" :value="student.newindex" :range="array" :data-current="index">
<view class="uni-input">{{array[student.newindex]}}</view>
</picker>
</view>
<view class="border"></view>
</block>
这是视图层,用到是for循环实现一个学生列表。对没有及时签到的学生可以进行选择,故需要用到picker。可是问题就来了,有多个picker,里面的{{array[index]}}显示的内容都是由data中的同一个index控制的,这样,每一次改变其中一个picker的值时,所有的picker都会改变值。这个问题困扰了我许久。当时我就想如果可以得到当前改变的picker的index就好了,这样就可以指定改变的picker了。但是当时的我不知道如何获取。
我的疑点有以下几点:
1.如何获取当前的index?本来也是可以的,用一个函数,参数为student,然后在函数里写index=e.index不就好了?可是这里绑定的函数是@change="bindPickerChange",和普通的绑定不一样,我不知道如何传参。
- 然后就是我不知到为何在method中的bindPickerChange又是有一个参数e的。我知道是自己基础不好,对e的认识很浅。我试图用console.log来获取e,看看其内部究竟有哪些值,但结果并不好。
- 能不能用data-XXX呢?其实如果是在微信小程序里面,我肯定首选这个,但是在uni-app里,我一直以为不能用data-XXX,因为官方文档似乎没有,网上也没有找到(我的搜索水平太差了),或者说这是默认就可以的。总之,我直到看了搭档这样用以后才知道原来uni-app是可以用的。当时我还很惊讶地问他是怎么知道的,他说还是当初学小程序的时候我教他的。卧槽,这么interesting的吗?
今天终于在一篇解决微信小程序的文章里找到了思路,也解决了之前的疑点。
其实以上三点都是一样的。因为data-xxx是可以用的,而在e里面就是可以看到data-xxx的,这就是答案。
studentlist2: [
{
newindex:0,
avatar: '/static/lishi.jpg',
name: '楚秋然',
id: '2017082314'
},
{
newindex:1,
avatar: '/static/xinli.jpg',
name: '愧泽',
id: '2017082315'
}
]
bindPickerChange: function(e) {
const curindex = e.target.dataset.current
console.log('picker发送选择改变,携带值为', e.target.value)
console.log('picker发送选择改变,携带值为', curindex)
this.studentlist2[curindex].newindex = e.target.value
console.log("index="+this.studentlist.index)
}
感觉自己是基础太差了。又没有人带,不然,这么easy的问题真的不该被卡住这么久。一个小白之所以会不自量力地写一篇文章也是想积累一些经验,和大家交流一下。而且,这个问题似乎都没有人写过,想着可能是太简单了没有必要写。但是如果有像我一样的小白,希望能对你有帮助。毕竟,当初的我是多么渴望有这么一篇文章来帮助我。
收起阅读 »
开了一个WordPress使用uni-app开发app和小程序的教程,来捧个场吧。
如题,开了一个WordPress使用uni-app开发app和小程序的教程,各位大神都来捧个场吧,主要巩固一下技术,顺便回馈一下小白,超级超级大神绕道,不喜勿喷啊!
看完此教程,你将学到什么:
- WordPress深度二开
- WordPress主题制作基础
- PHP基础
- 接口设计基础
- 用uni-app做一个属于你自己的app
教程目录(长期更新)
1、WordPress安装
2、开发一个简单的WordPress主题
3、使用uni-app框架创建一个app项目
4、用uni-app制作首页幻灯片
5、用WordPress编写app幻灯片接口
6、uni-app请求接口以及生命周期函数
7、uni-app渲染幻灯片数据
8、用uni-app制作首页文章列表
9、WordPress开发首页文章列表接口
10、uni-app:渲染app的首页文章数据
11、uni-app制作app底部导航栏
12、uni-app新建发现页面并加入底部tab
13、uni-app开发发现界面(九宫格布局)
14、WordPress开发发现界面接口
15、uni-app渲染发现界面
16、uni-app新建用户页面并加入tab
17、开始登录与注册
18、uni-app制作登录页面
19、WordPress开发登录接口
20、uni-app登录
21、uni-app开发注册页面【包含视频】
22、用WordPress开发注册接口【包含视频】(2020年02月19日,更新注册接口)
23、 实现注册功能
24、用户中心:为什么要使用Token?
25、实现Token第一步
27、实现Token第二步
28、封装Token类
29、uni-app实现用户是否登录的判断
30、uni-app实现登录保存Token
番外
官方交流群:824144151
问题解决
1、关于接口跨域问题
教程地址:
WordPress开发app(小程序)接口开发教程
技术援助
教程看不懂?需要一对一技术援助服务?点击这里
如题,开了一个WordPress使用uni-app开发app和小程序的教程,各位大神都来捧个场吧,主要巩固一下技术,顺便回馈一下小白,超级超级大神绕道,不喜勿喷啊!
看完此教程,你将学到什么:
- WordPress深度二开
- WordPress主题制作基础
- PHP基础
- 接口设计基础
- 用uni-app做一个属于你自己的app
教程目录(长期更新)
1、WordPress安装
2、开发一个简单的WordPress主题
3、使用uni-app框架创建一个app项目
4、用uni-app制作首页幻灯片
5、用WordPress编写app幻灯片接口
6、uni-app请求接口以及生命周期函数
7、uni-app渲染幻灯片数据
8、用uni-app制作首页文章列表
9、WordPress开发首页文章列表接口
10、uni-app:渲染app的首页文章数据
11、uni-app制作app底部导航栏
12、uni-app新建发现页面并加入底部tab
13、uni-app开发发现界面(九宫格布局)
14、WordPress开发发现界面接口
15、uni-app渲染发现界面
16、uni-app新建用户页面并加入tab
17、开始登录与注册
18、uni-app制作登录页面
19、WordPress开发登录接口
20、uni-app登录
21、uni-app开发注册页面【包含视频】
22、用WordPress开发注册接口【包含视频】(2020年02月19日,更新注册接口)
23、 实现注册功能
24、用户中心:为什么要使用Token?
25、实现Token第一步
27、实现Token第二步
28、封装Token类
29、uni-app实现用户是否登录的判断
30、uni-app实现登录保存Token
番外
官方交流群:824144151
问题解决
1、关于接口跨域问题
教程地址:
WordPress开发app(小程序)接口开发教程
技术援助
教程看不懂?需要一对一技术援助服务?点击这里
收起阅读 »