
uni-AD App端激励视频服务器回调使用指南
HBuilderX 2.7.0 版本起,uni-AD的激励视频广告支持穿山甲的服务器回调功能
HBuilderX 3.1.15 版本起,uni-AD的激励视频广告支持优量汇、快手的服务器回调功能
概述
激励视频服务端回调是指在用户看完激励视频达到奖励条件时,广告平台服务端会向开发者服务端发送一个验证请求,同时客户端会给出onVerify回调,开发者根据回调进行奖励发放,不同的广告平台onVerify回调和服务端验证请求时机不一样(比如:穿山甲的onVerify回调是在服务端验证请求之后进行的,优量汇和快手都是同时进行的),因为优量汇和快手的奖励回调onVerify事件和服务端验证请求是同时发送的,且开发者后台收到验证请求可能会有延迟或网络原因上的失败,所以开发者需要平衡用户体验与奖励验证。
相对来讲服务器回调将更加安全,可以依赖广告平台的反作弊机制来避免用户模拟观看广告完成的事件。
开通服务器回调
- 登录uni-AD后台
- 找到应用对应的广告位,配置激励视频
- 选择服务空间,如果没有点击新增即可
- 选择
业务在传统服务器
, 输入接收服务器回调的http地址
App端创建激励视频广告时传入回调参数
uni-app项目
https://uniapp.dcloud.io/api/a-d/rewarded-video
5+ App(WAP2APP)项目
创建激励视频广告plus.ad.createRewardedVideoAd时传入服务器回调数据urlCallback,示例如下:
adReward = plus.ad.createRewardedVideoAd({
adpid: '1507000689',
urlCallback: {
userId: 'test111111', //可选的透传参数
extra: 'testdata' //可选的透传参数
}
});
调用激励视频广告对象的onVerify监听服务器是否发送验证请求
穿山甲:
adReward.onVerify(function(e){
console.log('服务器发送验证请求且回调校验完成');
var provider= e.provider;
var valid = e.isValid; //获取校验结果
//valid为true表示通过了服务器的校验,false表示可能没有通过服务器的校验,或是服务器延迟或失败(此时需增加逻辑:轮询向服务器请求并验证结果)
});
优量汇:
adReward.onVerify(function(e){
console.log('服务器已发送验证请求');
var provider= e.provider;
var transId = e.transId;
需增加逻辑:轮询向服务器请求并验证结果
});
快手:
adReward.onVerify(function(e){
console.log('服务器已发送验证请求');
var provider= e.provider;
需增加逻辑:轮询向服务器请求并验证结果
});
HBuilderX 2.7.0 版本起,uni-AD的激励视频广告支持穿山甲的服务器回调功能
HBuilderX 3.1.15 版本起,uni-AD的激励视频广告支持优量汇、快手的服务器回调功能
概述
激励视频服务端回调是指在用户看完激励视频达到奖励条件时,广告平台服务端会向开发者服务端发送一个验证请求,同时客户端会给出onVerify回调,开发者根据回调进行奖励发放,不同的广告平台onVerify回调和服务端验证请求时机不一样(比如:穿山甲的onVerify回调是在服务端验证请求之后进行的,优量汇和快手都是同时进行的),因为优量汇和快手的奖励回调onVerify事件和服务端验证请求是同时发送的,且开发者后台收到验证请求可能会有延迟或网络原因上的失败,所以开发者需要平衡用户体验与奖励验证。
相对来讲服务器回调将更加安全,可以依赖广告平台的反作弊机制来避免用户模拟观看广告完成的事件。
开通服务器回调
- 登录uni-AD后台
- 找到应用对应的广告位,配置激励视频
- 选择服务空间,如果没有点击新增即可
- 选择
业务在传统服务器
, 输入接收服务器回调的http地址
App端创建激励视频广告时传入回调参数
uni-app项目
https://uniapp.dcloud.io/api/a-d/rewarded-video
5+ App(WAP2APP)项目
创建激励视频广告plus.ad.createRewardedVideoAd时传入服务器回调数据urlCallback,示例如下:
adReward = plus.ad.createRewardedVideoAd({
adpid: '1507000689',
urlCallback: {
userId: 'test111111', //可选的透传参数
extra: 'testdata' //可选的透传参数
}
});
调用激励视频广告对象的onVerify监听服务器是否发送验证请求
穿山甲:
adReward.onVerify(function(e){
console.log('服务器发送验证请求且回调校验完成');
var provider= e.provider;
var valid = e.isValid; //获取校验结果
//valid为true表示通过了服务器的校验,false表示可能没有通过服务器的校验,或是服务器延迟或失败(此时需增加逻辑:轮询向服务器请求并验证结果)
});
优量汇:
adReward.onVerify(function(e){
console.log('服务器已发送验证请求');
var provider= e.provider;
var transId = e.transId;
需增加逻辑:轮询向服务器请求并验证结果
});
快手:
adReward.onVerify(function(e){
console.log('服务器已发送验证请求');
var provider= e.provider;
需增加逻辑:轮询向服务器请求并验证结果
});
收起阅读 »

HbuilderX 的主题
基于 2.6.5.20200314
版,,不知道兼容性如何
主题太少了,好不容易找了一个,结果发现配色还不对,干脆自己来搞一个。
界面

使用
壹、 如果不会配置,请参考自定义主题教程
贰、 主题选择【雅蓝】
叁、 在编辑器顶部位置找到【工具 / 设置】进入
肆、 选择源码视图
伍、 键入以下代码
"[Atom One Dark]": {
// 文本编辑区
"editor.background": "#282c34",
// 分栏
"editorGroup.border": "rgba(0,0,0,0)",
// 代码助手
"editorSuggestWidget.highlightForeground": "#e5c07b",
// 预览按钮
"extensionButton.border": "#181a1f",
// 文本框
"focusBorder": "#464646",
"input.background": "#21252b",
// 标签卡
"tab.activeBackground": "#282c34",
"tab.activeForeground": "#dcdcdc",
"tab.border": "rgba(0,0,0,0)",
"tab.hoverBackground": "#323842",
"tab.inactiveBackground": "#21252b",
// 设置
"inputOption.activeBorder": "#464646",
"settings.dropdownBackground": "#181a1f",
"settings.dropdownBorder": "#464646",
"settings.dropdownListBorder": "#181a1f",
"settings.textInputBackground": "#181a1f",
"settings.textInputBorder": "#181a1f",
// 工具栏
"toolBar.background": "#21252b",
"toolBar.border": "rgba(0,0,0,0)",
"toolBar.hoverBackground": "#2c313a",
// 控制台
"terminal.background": "#21252b",
"console.background": "#21252b",
"panelTitle.activeForeground": "#cccccc",
"debug.foreground": "#cccccc"
}
基于 2.6.5.20200314
版,,不知道兼容性如何
主题太少了,好不容易找了一个,结果发现配色还不对,干脆自己来搞一个。
界面
使用
壹、 如果不会配置,请参考自定义主题教程
贰、 主题选择【雅蓝】
叁、 在编辑器顶部位置找到【工具 / 设置】进入
肆、 选择源码视图
伍、 键入以下代码
"[Atom One Dark]": {
// 文本编辑区
"editor.background": "#282c34",
// 分栏
"editorGroup.border": "rgba(0,0,0,0)",
// 代码助手
"editorSuggestWidget.highlightForeground": "#e5c07b",
// 预览按钮
"extensionButton.border": "#181a1f",
// 文本框
"focusBorder": "#464646",
"input.background": "#21252b",
// 标签卡
"tab.activeBackground": "#282c34",
"tab.activeForeground": "#dcdcdc",
"tab.border": "rgba(0,0,0,0)",
"tab.hoverBackground": "#323842",
"tab.inactiveBackground": "#21252b",
// 设置
"inputOption.activeBorder": "#464646",
"settings.dropdownBackground": "#181a1f",
"settings.dropdownBorder": "#464646",
"settings.dropdownListBorder": "#181a1f",
"settings.textInputBackground": "#181a1f",
"settings.textInputBorder": "#181a1f",
// 工具栏
"toolBar.background": "#21252b",
"toolBar.border": "rgba(0,0,0,0)",
"toolBar.hoverBackground": "#2c313a",
// 控制台
"terminal.background": "#21252b",
"console.background": "#21252b",
"panelTitle.activeForeground": "#cccccc",
"debug.foreground": "#cccccc"
}
收起阅读 »

专业承接/电商APP定制开发、团队开发电商APP开发有哪些功能?
一、商品展示的功能
商品展示是电商APP最核心的部分,商家通过视频、图片、文字等方式向消费者展示商品,向消费者展示商城以及商品的优势,来吸引消费者购买。
二、搜索商品的功能
三、商品分类的功能
四、商品推荐的功能
五、在线咨询的功能
六、收藏商品的功能
七、分享商品的功能
八、加入购物车的功能
九、在线支付的功能
十、订单管理的功能
十一、查看物流的功能
一、商品展示的功能
商品展示是电商APP最核心的部分,商家通过视频、图片、文字等方式向消费者展示商品,向消费者展示商城以及商品的优势,来吸引消费者购买。
二、搜索商品的功能
三、商品分类的功能
四、商品推荐的功能
五、在线咨询的功能
六、收藏商品的功能
七、分享商品的功能
八、加入购物车的功能
九、在线支付的功能
十、订单管理的功能
十一、查看物流的功能

分享uniapp使用原生Android推送消息(内推)以及点击通知监听数据
前言
由于用uniapp官方的plus.push.createMessage()在Android平台下推送通知无法显示推送时间,需要调用原生Android推送通知。
在社区综合了各大神的代码,具体如下:
推送
推送事件:
/**
* android原生通知发送
* @param content 通知内容
* @param data json对象,存储通知的隐藏数据,用于点击通知时接收使用
*/
android_notify(content = '', data = {}) {
// #ifdef APP-PLUS
var title = '通知标题';
console.log('准备通知');
console.log(plus.os.name);
//Android平台下才使用此推送
if (plus.os.name != 'Android') {
return false;
}
//随机生成通知ID
var NotifyID = Math.floor(Math.random() * 10000) + 1;
var main = plus.android.runtimeMainActivity();
var Context = plus.android.importClass("android.content.Context");
var NotificationManager = plus.android.importClass("android.app.NotificationManager");
var nm = main.getSystemService(Context.NOTIFICATION_SERVICE);
var Notification = plus.android.importClass("android.app.Notification");
var Intent = plus.android.importClass("android.content.Intent");
var PendingIntent = plus.android.importClass("android.app.PendingIntent");
var intent = new Intent(main, main.getClass());
//传递参数
var payload = {
'msg':content,
'notify_id':NotifyID,
'data':data
};
intent.putExtra("receive", JSON.stringify(payload));
//PendingIntent.getActivity的第二个参数需要设置为随机数,否则多个通知时会导致前面的通知被后面的通知替换Extra的数据
var pendingIntent = PendingIntent.getActivity(main, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
var SystemVersion = plus.os.version;
var firstVersionNumber = Number(SystemVersion.split('.')[0]);
var r = plus.android.importClass("android.R");
var mNotification;
//判断当前系统版本在8.0及以上
if (firstVersionNumber >= 8){
var NotificationChannel = plus.android.importClass('android.app.NotificationChannel');
var channel = new NotificationChannel("s"+ NotifyID, "1", NotificationManager.IMPORTANCE_HIGH);
nm.createNotificationChannel(channel);
Notification = plus.android.importClass("android.support.v4.app.NotificationCompat");
mNotification = new Notification.Builder(main, "s" + NotifyID);
} else {
Notification = plus.android.importClass("android.app.Notification");
mNotification = new Notification.Builder(main);
}
mNotification.setContentTitle(title) //设置标题
mNotification.setContentText(content); //设置内容
//mNotification.setSubText(''); //子内容暂时去掉
mNotification.setAutoCancel(true); //设置点击消失
mNotification.setShowWhen(true); //显示通知时间,貌似不加这句也能显示
mNotification.setTicker("PadInfo"); //弹出通知
mNotification.setSmallIcon(17301620); //设置当前app图标
//mNotification.setDefaults(Notification.DEFAULT_VIBRATE); //声音、闪灯、震动效果,可叠加,此语句无效
mNotification.setPriority(Notification.PRIORITY_DEFAULT); //通知优先级
mNotification.flags=Notification.FLAG_ONLY_ALERT_ONCE; //发起通知时震动
mNotification.setContentIntent(pendingIntent);
var mNb = mNotification.build();
//判断当前系统版本在8.0及以上
if (firstVersionNumber >= 8){
nm.notify("s" + NotifyID, NotifyID, mNb);
} else {
nm.notify(NotifyID, mNb);
}
//void plus.device.beep(2);//bee bee叫
plus.device.vibrate(300);//震动
console.log('通知结束');
return true;
// #endif
}
调用方法:
android_notify('test', {
params1: 'params1',
params2: 'params2',
params3: 'params3',
params4: 'params4'
});
接收
点击通知接收通知数据
/**
* android原生通知接收
*/
android_receive() {
// #ifdef APP-PLUS
if (plus.os.name != 'Android') {
return false;
}
//android原生通知栏接收器(程序退出后无效)
var main = plus.android.runtimeMainActivity();
var intent = main.getIntent();
var message = intent && intent.getExtra != undefined ? intent.getExtra("receive") : null;
console.log(message);
message = message ? JSON.parse(message) : '';
if (message) {
//删除当前通知
// var Context = plus.android.importClass("android.content.Context");
// var nm = main.getSystemService(Context.NOTIFICATION_SERVICE);
// console.log(message.notify_id);
//nm.cancel('s' + message.notify_id, message.notify_id);//安卓版本大于等于8的
//nm.cancel(message.notify_id);//安卓版本小于8的
// nm.cancelAll();
//把消息数据置空,以免再次打开APP时重复执行此处
intent.putExtra("receive", '');
var params = message.data;
if (params1 == 'xxx') {
//TODO do something.
} else if (params1 == 'yyy') {
//TODO do something.
}
}
// #endif
}
调用方法
// App.Vue
onShow: function() {
...
// #ifdef APP-PLUS
android_receive();
// #endif
...
},
注意事项
- 已知问题:第一次通知会有通知延迟现象,大概2-3秒后才会收到通知,之后就不会了(官方的推送没有此问题);
- 程序被关闭后点击通知消息无法再接收到通知的数据(暂时没有好的解决方案,如果大家有好的方法,欢迎回复分享);
希望能帮助大家。
-
2020年4月3日补充:
-
多行显示通知消息
//创建大文本样式
var bigTextStyle = plus.android.importClass("android.support.v4.app.NotificationCompat$BigTextStyle");
var style = new bigTextStyle();
style.setBigContentTitle(title);
// style.setSummaryText("备注一行");
style.bigText(content);//这里可以设置超长的文本
mNotification.setStyle(style); //设置大文本样式
以上代码放到var mNb = mNotification.build();
之前即可
前言
由于用uniapp官方的plus.push.createMessage()在Android平台下推送通知无法显示推送时间,需要调用原生Android推送通知。
在社区综合了各大神的代码,具体如下:
推送
推送事件:
/**
* android原生通知发送
* @param content 通知内容
* @param data json对象,存储通知的隐藏数据,用于点击通知时接收使用
*/
android_notify(content = '', data = {}) {
// #ifdef APP-PLUS
var title = '通知标题';
console.log('准备通知');
console.log(plus.os.name);
//Android平台下才使用此推送
if (plus.os.name != 'Android') {
return false;
}
//随机生成通知ID
var NotifyID = Math.floor(Math.random() * 10000) + 1;
var main = plus.android.runtimeMainActivity();
var Context = plus.android.importClass("android.content.Context");
var NotificationManager = plus.android.importClass("android.app.NotificationManager");
var nm = main.getSystemService(Context.NOTIFICATION_SERVICE);
var Notification = plus.android.importClass("android.app.Notification");
var Intent = plus.android.importClass("android.content.Intent");
var PendingIntent = plus.android.importClass("android.app.PendingIntent");
var intent = new Intent(main, main.getClass());
//传递参数
var payload = {
'msg':content,
'notify_id':NotifyID,
'data':data
};
intent.putExtra("receive", JSON.stringify(payload));
//PendingIntent.getActivity的第二个参数需要设置为随机数,否则多个通知时会导致前面的通知被后面的通知替换Extra的数据
var pendingIntent = PendingIntent.getActivity(main, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
var SystemVersion = plus.os.version;
var firstVersionNumber = Number(SystemVersion.split('.')[0]);
var r = plus.android.importClass("android.R");
var mNotification;
//判断当前系统版本在8.0及以上
if (firstVersionNumber >= 8){
var NotificationChannel = plus.android.importClass('android.app.NotificationChannel');
var channel = new NotificationChannel("s"+ NotifyID, "1", NotificationManager.IMPORTANCE_HIGH);
nm.createNotificationChannel(channel);
Notification = plus.android.importClass("android.support.v4.app.NotificationCompat");
mNotification = new Notification.Builder(main, "s" + NotifyID);
} else {
Notification = plus.android.importClass("android.app.Notification");
mNotification = new Notification.Builder(main);
}
mNotification.setContentTitle(title) //设置标题
mNotification.setContentText(content); //设置内容
//mNotification.setSubText(''); //子内容暂时去掉
mNotification.setAutoCancel(true); //设置点击消失
mNotification.setShowWhen(true); //显示通知时间,貌似不加这句也能显示
mNotification.setTicker("PadInfo"); //弹出通知
mNotification.setSmallIcon(17301620); //设置当前app图标
//mNotification.setDefaults(Notification.DEFAULT_VIBRATE); //声音、闪灯、震动效果,可叠加,此语句无效
mNotification.setPriority(Notification.PRIORITY_DEFAULT); //通知优先级
mNotification.flags=Notification.FLAG_ONLY_ALERT_ONCE; //发起通知时震动
mNotification.setContentIntent(pendingIntent);
var mNb = mNotification.build();
//判断当前系统版本在8.0及以上
if (firstVersionNumber >= 8){
nm.notify("s" + NotifyID, NotifyID, mNb);
} else {
nm.notify(NotifyID, mNb);
}
//void plus.device.beep(2);//bee bee叫
plus.device.vibrate(300);//震动
console.log('通知结束');
return true;
// #endif
}
调用方法:
android_notify('test', {
params1: 'params1',
params2: 'params2',
params3: 'params3',
params4: 'params4'
});
接收
点击通知接收通知数据
/**
* android原生通知接收
*/
android_receive() {
// #ifdef APP-PLUS
if (plus.os.name != 'Android') {
return false;
}
//android原生通知栏接收器(程序退出后无效)
var main = plus.android.runtimeMainActivity();
var intent = main.getIntent();
var message = intent && intent.getExtra != undefined ? intent.getExtra("receive") : null;
console.log(message);
message = message ? JSON.parse(message) : '';
if (message) {
//删除当前通知
// var Context = plus.android.importClass("android.content.Context");
// var nm = main.getSystemService(Context.NOTIFICATION_SERVICE);
// console.log(message.notify_id);
//nm.cancel('s' + message.notify_id, message.notify_id);//安卓版本大于等于8的
//nm.cancel(message.notify_id);//安卓版本小于8的
// nm.cancelAll();
//把消息数据置空,以免再次打开APP时重复执行此处
intent.putExtra("receive", '');
var params = message.data;
if (params1 == 'xxx') {
//TODO do something.
} else if (params1 == 'yyy') {
//TODO do something.
}
}
// #endif
}
调用方法
// App.Vue
onShow: function() {
...
// #ifdef APP-PLUS
android_receive();
// #endif
...
},
注意事项
- 已知问题:第一次通知会有通知延迟现象,大概2-3秒后才会收到通知,之后就不会了(官方的推送没有此问题);
- 程序被关闭后点击通知消息无法再接收到通知的数据(暂时没有好的解决方案,如果大家有好的方法,欢迎回复分享);
希望能帮助大家。
-
2020年4月3日补充:
-
多行显示通知消息
//创建大文本样式
var bigTextStyle = plus.android.importClass("android.support.v4.app.NotificationCompat$BigTextStyle");
var style = new bigTextStyle();
style.setBigContentTitle(title);
// style.setSummaryText("备注一行");
style.bigText(content);//这里可以设置超长的文本
mNotification.setStyle(style); //设置大文本样式
以上代码放到var mNb = mNotification.build();
之前即可

uniapp打包成H5样式不生效问题
本来用uniapp写个小程序的,因为需求需要打包成H5,本来以为不会有什么问题的,打包完成之后发现一个button的样式没有了,原来该button的样式是通过id绑定的,后来折腾了半天都没有用,改成class绑定样式就可以了
本来用uniapp写个小程序的,因为需求需要打包成H5,本来以为不会有什么问题的,打包完成之后发现一个button的样式没有了,原来该button的样式是通过id绑定的,后来折腾了半天都没有用,改成class绑定样式就可以了

小团队承接APP定制开发项目、iOS、安卓版均可开发
小团队承接APP定制开发项目、iOS、安卓均可开发
首先提供项目整体需求逻辑;需求确认;
计算工期报价以及开发人员配备;
签订合同按合同约定支付合同款项;
线稿图、UI设计图确认;
UI设计图确认后,签订确认书;
前端代码编写切图;
后台搭建完成开发;
本团队开始测试,测试完毕无误后,交由客户进行测试;
客户测试无误,开始安排项目对接,后台不需要的数据进行清除;
客户安排上线时间,进行上线;
小团队承接APP定制开发项目、iOS、安卓均可开发
首先提供项目整体需求逻辑;需求确认;
计算工期报价以及开发人员配备;
签订合同按合同约定支付合同款项;
线稿图、UI设计图确认;
UI设计图确认后,签订确认书;
前端代码编写切图;
后台搭建完成开发;
本团队开始测试,测试完毕无误后,交由客户进行测试;
客户测试无误,开始安排项目对接,后台不需要的数据进行清除;
客户安排上线时间,进行上线;

websocket IM聊天教程-教你用GoEasy快速实现IM聊天
经常有朋友问起GoEasy如何实现IM,今天就手把手的带大家从头到尾用GoEasy实现一个完整IM聊天,全套代码已经放在了github。
uniapp im即时聊天demo:https://ext.dcloud.net.cn/plugin?id=5177
今日的前端技术发展可谓百花争鸣,为了确保本文能帮助到使用任何技术栈的前端工程师,Demo的源码实现上选择了最简单的HTML+JQuery的方式,所以,不论您是准备用Uniapp开发移动APP,还是准备写个小程序,不论你喜欢用React还是VUE,还是React-native或ionic, 或者您直接用原生Javascript和Typescript,都是可以轻松理解,全套代码已经放在github上了,下载后不需要搭建任何环境,直接用浏览器打开,就可以用来聊天了。
作为一名程序员,在编码之前,首先要做的当然是架构设计!什么?确认不是装逼?当然,别忘了星爷的那句话:我是一名程序员!没有思想的程序员,跟咸鱼有什么区别呢?
咳咳咳,正文开始:
首先我们代码层将整个功能分为四层:
1、华丽的展示层(index.html):你们负责功能优雅强大,我负责貌美如花。展示层其实就是纯静态的html,显示界面,高端点说,就是负责人机交互的。
2、承上启下的控制层(controller.js): 控制层作用就是接受页面操作的参数,调用service层,根据页面的操作指令或者service层的反馈,负责对页面的展示做出控制。不可以编写任何与展示逻辑无关的代码,也就是不能侵入任何业务逻辑。衡量这一层做的好不好的的标准,就是假设删掉controller和view层,service能准确完整的描述所有的业务逻辑。
3、运筹帷幄的关键核心业务层(service.js): 接受controller层的指令,实现业务逻辑,必要时候调用goeasy提供网络通讯支持,或调用restapi层完成数据的查询和保存。这一层包含所有的业务逻辑,任何业务逻辑相关的代码,都不可以漏到其他层,确保只要service存在,整个项目的灵魂就存在,确保service层完全是原生代码实现业务逻辑,而没有类似于vue或者小程序前端框架的语法和代码渗入,从而达到service层能够在任何前端框架通用。
4、神通广大的服务器交互层(restapi.js): 根据传入的参数完成服务器端接口的调用,来实现数据查询或、修改或保存,并且返回结果,不参与任何业务逻辑。在实践中大部分是负责发送http请求和服务器交互。
分层的目标就是为了确保除了在核心业务层以外的其他层次能够被轻易的替换。举例:我们当前的版本是使用html+jquery完成,如果希望再开发一个Uniapp实现的小程序或者app,只需要用Uniapp画个新外壳,对controller层做一些修改,就可轻松完成一个小程序或者APP版的IM聊天,不需要对service和restapi做任何修改 。同理,如果服务器端发生变化,或者更换了与服务器的交互方式,只需要对restapi做出修改,其他三层则不受任何影响。
OK, 有了如此清晰而优秀的代码结构分层设计,就差一段优雅的代码来实现了。
Ready, Go! 编码开始:
1、登录页面
这个最简单,闭着眼睛画个界面,用户名密码正确后,完成以下几个步骤。
1.1. 根据用户名查询出来的用户,初始化全局变量:当前用户。
1.2. 将controller层的onNewMessage, onFriendOnline,onFriendOffline赋值给service 。
1.3. new goeasy建立长连接,记得要传入userid。如需在subscriberPrencese用户上下线提醒事件,或者在调用HereNow获取在线用户列表时,能拿到userId以外,更多的信息,可以在userdata里传入。
1.4. 调用restapi,查询该用户的好友列表,根据结果初始化本地好友列表friendlist。
1.5. 循环好友,以friendUUID为channel,调用subscriberPrencense,监听所有好友的上下线事件。
1.6. 以当前用户的uuid为channel,调用subscriber,监听来自所有好友发来的消息。
1.7. 显示好友列表界面。
1.8. 初始化好友的在线状态,以数组形式传入所有好友的userId,调用hereNowByUserIds,获得当前在线的好友列表,根据结果将friendlist里属于在线状态的friend的在线状态改为true,同时将界面上在线用户的头像改为彩色。
2、显示好友列表(1.7)
2.1. service层获取当前用户信息,在页面显示当前用户的username和头像。
2.2. service获取本地好友列表,然后controller将每个好友的头像和名称显示到页面上,对于当前在线的用户,旁边显示一个小绿点,并且为每个好友绑定一个点击事件,点击好友时,显示聊天界面, 如果该好友有未读消息的,红色小气泡显示未读消息数量。
3、点击一个好友,进入与其聊天的界面
3.1. 窗口顶部显示聊天好友的名称。
3.2. 调用restapi根据当前用户的UUID和好友的friendUUID,查询与该好友的聊天记录,如果这个聊天记录的sender是自己,就显示在页面的右边,如果是朋友发的,则显示在左边。
3.3. 将该好友在本地数据里未读消息恢复为0。
3.4. 并且将聊天记录滚动到最下边。
3.5. 如果点击返回,就直接调进入第二步。
4、在聊天界面,输入消息后发送
4.1. 当前用户uuid作为senderUUID和消息内容组成chatMessage。
4.2. 调用restapi将chatMessage发往“服务器”端,我们建议的方式是所有的消息发往自己的服务器端,在服务器端先保存入库,然后在服务端publish。具体做法是将chatMessage转换为字符串,入库,然后将该好友的channel作为channel调用GoEasy完成publish。(当然,你会发现在我们的示例代码这个过程是在restapi里直接完成的,原因是为了demo的演示方便,我们模拟的服务器端行为,相信你懂的)
4.3. 自己的消息发送成功后,显示在聊天窗口的右边。
5、收到新消息
5.1. 在1.6定义了接收好友新消息的事件,当收到一条好友的新消息时。
5.2. 首先调用restapi保存到服务器。
5.3. 本地好友数据里的未读消息加1。
5.4. 如果当前界面是好友列表,将来自该朋友的未读消息的数字显示在界面上。
5.5. 如果收到的消息就是来自当前对话窗口,就将消息显示到聊天窗口,并且调用service将本地数据里该好友的未读消息清0。
6、用户上下线提醒
6.1. 在1.5监听了用户上下线,当收到一个用户上线或下线的通知后(注意返回的是一个列表,一次事件有可能有多个好友都发生了状态变化)。
6.2. 修改将本地数据里该好友对象在线状态,如果是上线事件就显示彩色,如果是下线就显示黑白色。
至此,整个聊天功能就完成了,是不是很简单呢。在整个demo中只用到了goeasy的四个API:subscriber(接收消息),subscriberPrencense(接受上下线通知),hereNowByUserIds(获取当前在线用户列表), publish(发送消息)。详情可以参考goeasy官方文档https://www.goeasy.io/cn/developers.html
注意事项:
1.在restapi.js 里 可以找到用户名和密码
2.在service.js里将appkey替换为您自己的common key
3.subscriberPrencense和hereNowByUserIds这两个方法,默认是关闭的,需要扫码添加GoEasy客服开通哦~
将代码与本文一起对照阅读后,要写个IM,比画个0还简单,如果使用的是其他的前端技术框架如小程序和React-native,只需要重新画个外壳就好了!什么,你不相信?如果觉得你被骗了,请扫码添加微信好友,欢迎吐槽!没有您暴风雨般的吐槽和春风一般的赞美,我如何进步呢?
彩弹在最后:
看了代码的你,是不是发现我们的RESTAPI其实是个冒牌货,并不会真的和远程的某个服务器交互,这是为了方便演示,我们定义了两个变量来帮助模拟远程数据的查询,然后用localstorage来模拟服务器的保存,相信聪明的你,肯定已经get到我们的代码思路了。
GoEasy系列教程:
经常有朋友问起GoEasy如何实现IM,今天就手把手的带大家从头到尾用GoEasy实现一个完整IM聊天,全套代码已经放在了github。
uniapp im即时聊天demo:https://ext.dcloud.net.cn/plugin?id=5177
今日的前端技术发展可谓百花争鸣,为了确保本文能帮助到使用任何技术栈的前端工程师,Demo的源码实现上选择了最简单的HTML+JQuery的方式,所以,不论您是准备用Uniapp开发移动APP,还是准备写个小程序,不论你喜欢用React还是VUE,还是React-native或ionic, 或者您直接用原生Javascript和Typescript,都是可以轻松理解,全套代码已经放在github上了,下载后不需要搭建任何环境,直接用浏览器打开,就可以用来聊天了。
作为一名程序员,在编码之前,首先要做的当然是架构设计!什么?确认不是装逼?当然,别忘了星爷的那句话:我是一名程序员!没有思想的程序员,跟咸鱼有什么区别呢?
咳咳咳,正文开始:
首先我们代码层将整个功能分为四层:
1、华丽的展示层(index.html):你们负责功能优雅强大,我负责貌美如花。展示层其实就是纯静态的html,显示界面,高端点说,就是负责人机交互的。
2、承上启下的控制层(controller.js): 控制层作用就是接受页面操作的参数,调用service层,根据页面的操作指令或者service层的反馈,负责对页面的展示做出控制。不可以编写任何与展示逻辑无关的代码,也就是不能侵入任何业务逻辑。衡量这一层做的好不好的的标准,就是假设删掉controller和view层,service能准确完整的描述所有的业务逻辑。
3、运筹帷幄的关键核心业务层(service.js): 接受controller层的指令,实现业务逻辑,必要时候调用goeasy提供网络通讯支持,或调用restapi层完成数据的查询和保存。这一层包含所有的业务逻辑,任何业务逻辑相关的代码,都不可以漏到其他层,确保只要service存在,整个项目的灵魂就存在,确保service层完全是原生代码实现业务逻辑,而没有类似于vue或者小程序前端框架的语法和代码渗入,从而达到service层能够在任何前端框架通用。
4、神通广大的服务器交互层(restapi.js): 根据传入的参数完成服务器端接口的调用,来实现数据查询或、修改或保存,并且返回结果,不参与任何业务逻辑。在实践中大部分是负责发送http请求和服务器交互。
分层的目标就是为了确保除了在核心业务层以外的其他层次能够被轻易的替换。举例:我们当前的版本是使用html+jquery完成,如果希望再开发一个Uniapp实现的小程序或者app,只需要用Uniapp画个新外壳,对controller层做一些修改,就可轻松完成一个小程序或者APP版的IM聊天,不需要对service和restapi做任何修改 。同理,如果服务器端发生变化,或者更换了与服务器的交互方式,只需要对restapi做出修改,其他三层则不受任何影响。
OK, 有了如此清晰而优秀的代码结构分层设计,就差一段优雅的代码来实现了。
Ready, Go! 编码开始:
1、登录页面
这个最简单,闭着眼睛画个界面,用户名密码正确后,完成以下几个步骤。
1.1. 根据用户名查询出来的用户,初始化全局变量:当前用户。
1.2. 将controller层的onNewMessage, onFriendOnline,onFriendOffline赋值给service 。
1.3. new goeasy建立长连接,记得要传入userid。如需在subscriberPrencese用户上下线提醒事件,或者在调用HereNow获取在线用户列表时,能拿到userId以外,更多的信息,可以在userdata里传入。
1.4. 调用restapi,查询该用户的好友列表,根据结果初始化本地好友列表friendlist。
1.5. 循环好友,以friendUUID为channel,调用subscriberPrencense,监听所有好友的上下线事件。
1.6. 以当前用户的uuid为channel,调用subscriber,监听来自所有好友发来的消息。
1.7. 显示好友列表界面。
1.8. 初始化好友的在线状态,以数组形式传入所有好友的userId,调用hereNowByUserIds,获得当前在线的好友列表,根据结果将friendlist里属于在线状态的friend的在线状态改为true,同时将界面上在线用户的头像改为彩色。
2、显示好友列表(1.7)
2.1. service层获取当前用户信息,在页面显示当前用户的username和头像。
2.2. service获取本地好友列表,然后controller将每个好友的头像和名称显示到页面上,对于当前在线的用户,旁边显示一个小绿点,并且为每个好友绑定一个点击事件,点击好友时,显示聊天界面, 如果该好友有未读消息的,红色小气泡显示未读消息数量。
3、点击一个好友,进入与其聊天的界面
3.1. 窗口顶部显示聊天好友的名称。
3.2. 调用restapi根据当前用户的UUID和好友的friendUUID,查询与该好友的聊天记录,如果这个聊天记录的sender是自己,就显示在页面的右边,如果是朋友发的,则显示在左边。
3.3. 将该好友在本地数据里未读消息恢复为0。
3.4. 并且将聊天记录滚动到最下边。
3.5. 如果点击返回,就直接调进入第二步。
4、在聊天界面,输入消息后发送
4.1. 当前用户uuid作为senderUUID和消息内容组成chatMessage。
4.2. 调用restapi将chatMessage发往“服务器”端,我们建议的方式是所有的消息发往自己的服务器端,在服务器端先保存入库,然后在服务端publish。具体做法是将chatMessage转换为字符串,入库,然后将该好友的channel作为channel调用GoEasy完成publish。(当然,你会发现在我们的示例代码这个过程是在restapi里直接完成的,原因是为了demo的演示方便,我们模拟的服务器端行为,相信你懂的)
4.3. 自己的消息发送成功后,显示在聊天窗口的右边。
5、收到新消息
5.1. 在1.6定义了接收好友新消息的事件,当收到一条好友的新消息时。
5.2. 首先调用restapi保存到服务器。
5.3. 本地好友数据里的未读消息加1。
5.4. 如果当前界面是好友列表,将来自该朋友的未读消息的数字显示在界面上。
5.5. 如果收到的消息就是来自当前对话窗口,就将消息显示到聊天窗口,并且调用service将本地数据里该好友的未读消息清0。
6、用户上下线提醒
6.1. 在1.5监听了用户上下线,当收到一个用户上线或下线的通知后(注意返回的是一个列表,一次事件有可能有多个好友都发生了状态变化)。
6.2. 修改将本地数据里该好友对象在线状态,如果是上线事件就显示彩色,如果是下线就显示黑白色。
至此,整个聊天功能就完成了,是不是很简单呢。在整个demo中只用到了goeasy的四个API:subscriber(接收消息),subscriberPrencense(接受上下线通知),hereNowByUserIds(获取当前在线用户列表), publish(发送消息)。详情可以参考goeasy官方文档https://www.goeasy.io/cn/developers.html
注意事项:
1.在restapi.js 里 可以找到用户名和密码
2.在service.js里将appkey替换为您自己的common key
3.subscriberPrencense和hereNowByUserIds这两个方法,默认是关闭的,需要扫码添加GoEasy客服开通哦~
将代码与本文一起对照阅读后,要写个IM,比画个0还简单,如果使用的是其他的前端技术框架如小程序和React-native,只需要重新画个外壳就好了!什么,你不相信?如果觉得你被骗了,请扫码添加微信好友,欢迎吐槽!没有您暴风雨般的吐槽和春风一般的赞美,我如何进步呢?
彩弹在最后:
看了代码的你,是不是发现我们的RESTAPI其实是个冒牌货,并不会真的和远程的某个服务器交互,这是为了方便演示,我们定义了两个变量来帮助模拟远程数据的查询,然后用localstorage来模拟服务器的保存,相信聪明的你,肯定已经get到我们的代码思路了。
GoEasy系列教程:

使用native.js for ios如何获取bundleId
相对于native.js for android来说,native.js for ios对objective-c封装以后提供给我们的方法要少得多,基本上属于我们得知道objective-c怎么写,才能用native.js for ios来improtClass一个类,还得知道类下的所有方法,才能正常得使用。
下面就是使用 native.js for ios 获取应用bundleId的方式:
// 判断系统类型
if (plus.os.name === 'Android') {
// 获取安卓应用包名
packageName = plus.android.runtimeMainActivity().getPackageName()
} else {
// 获取苹果应用包名(bundleId)
packageName = plus.ios.importClass('NSBundle').mainBundle().bundleIdentifier()
}
相对于native.js for android来说,native.js for ios对objective-c封装以后提供给我们的方法要少得多,基本上属于我们得知道objective-c怎么写,才能用native.js for ios来improtClass一个类,还得知道类下的所有方法,才能正常得使用。
下面就是使用 native.js for ios 获取应用bundleId的方式:
// 判断系统类型
if (plus.os.name === 'Android') {
// 获取安卓应用包名
packageName = plus.android.runtimeMainActivity().getPackageName()
} else {
// 获取苹果应用包名(bundleId)
packageName = plus.ios.importClass('NSBundle').mainBundle().bundleIdentifier()
}
收起阅读 »

uniapp电影app作品展示 分享
从当初的 5+ 到 uniapp第一版 流应用 ,到现在最新uni-app,一直使用dc家 的产品制作app。
最近做了个影视app玩,不得不说uniapp确实强大。
首页用的vue写的,轮播也是再hllo uniapp 找的。顺便做了个下拉刷新。
分类 页页很方便。上拉加载更多,一句代码就解决了。
至于播放器,功能页很多,也可以直接用官方的。当然播放器肯定也能播放 直播流。
倍速,投屏,弹幕,自然都可以实现。
这里的难点 我想就是线路切换问题,很容易绕晕。
而且很多人有解析,有切片,有的还是对接别人的api,也有一次传完数据,也有点一集传一集的api。
搜索界面使用的 nvue ,这里用到了input ,这些几乎都不用写,直接导入复制黏贴就行。
打开页面 自带加载效果。
再说说网页功能,uniapp已经集成 x5内核,同时影视站长关心的网页播放器也得到了解决
上面界面就是和腾讯产品里的播放器一模一样。
好了,介绍这么多。希望大家支持国产,有兴趣的伙伴可以加入我们的qq群343440607,一起开发app
从当初的 5+ 到 uniapp第一版 流应用 ,到现在最新uni-app,一直使用dc家 的产品制作app。
最近做了个影视app玩,不得不说uniapp确实强大。
首页用的vue写的,轮播也是再hllo uniapp 找的。顺便做了个下拉刷新。
分类 页页很方便。上拉加载更多,一句代码就解决了。
至于播放器,功能页很多,也可以直接用官方的。当然播放器肯定也能播放 直播流。
倍速,投屏,弹幕,自然都可以实现。
这里的难点 我想就是线路切换问题,很容易绕晕。
而且很多人有解析,有切片,有的还是对接别人的api,也有一次传完数据,也有点一集传一集的api。
搜索界面使用的 nvue ,这里用到了input ,这些几乎都不用写,直接导入复制黏贴就行。
打开页面 自带加载效果。
再说说网页功能,uniapp已经集成 x5内核,同时影视站长关心的网页播放器也得到了解决
上面界面就是和腾讯产品里的播放器一模一样。
好了,介绍这么多。希望大家支持国产,有兴趣的伙伴可以加入我们的qq群343440607,一起开发app

想购买几个已上架有一定用户访问量的uniapp
想购买几个已上架有一定用户访问量的uniapp
感兴趣的加下微信,done2008
想购买几个已上架有一定用户访问量的uniapp
感兴趣的加下微信,done2008