HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

蓝蘑云直播实时音视频集成指南

原生插件 直播

准备:

  1. 通过官方途径申请蓝蘑云账号,参考使用指南;
  2. 离线SDK 或者插件市场获取;
  3. API参考文档;
  4. 参考DEMOgithub源码,或者插件市场获取;

DEMO运行示例

  1. 下载DEMO源码从插件市场下载,解压打开;
  2. 打开HBuild工具导入demo工程,从自己账号获取DCloud AppID;

  1. 获取蓝蘑云APPID,填入代码中 export const appId = ""

  1. 配置App原生插件;

  1. 配置HBuild android权限




android 6.0以上需要手动添加权限,我们sdk 提供接口获取权限接口

5.云打包


6.android demo 体验下载地址

注意事项

  1. 当前调试运行环境只支持真机调试运行,不能支持模拟器环境运行;
  2. 运行时确保app的摄像头和麦克风权限打开;如果加入房间失败,监听错误码为4007,代表无权限,需要在app权限设置里打开;
继续阅读 »

准备:

  1. 通过官方途径申请蓝蘑云账号,参考使用指南;
  2. 离线SDK 或者插件市场获取;
  3. API参考文档;
  4. 参考DEMOgithub源码,或者插件市场获取;

DEMO运行示例

  1. 下载DEMO源码从插件市场下载,解压打开;
  2. 打开HBuild工具导入demo工程,从自己账号获取DCloud AppID;

  1. 获取蓝蘑云APPID,填入代码中 export const appId = ""

  1. 配置App原生插件;

  1. 配置HBuild android权限




android 6.0以上需要手动添加权限,我们sdk 提供接口获取权限接口

5.云打包


6.android demo 体验下载地址

注意事项

  1. 当前调试运行环境只支持真机调试运行,不能支持模拟器环境运行;
  2. 运行时确保app的摄像头和麦克风权限打开;如果加入房间失败,监听错误码为4007,代表无权限,需要在app权限设置里打开;
收起阅读 »

蓝蘑云使用指南

概述:

maple-rtc 为蓝蘑云推出的直播&实时音视频系统,包括了直播,实时音频,视频,变声,美颜等功能,适用于娱乐,游戏,教育等实时场景中;Maple-RTC支持快速私有化部署,一键部署上线。

第一步:开通蓝蘑云服务

  1. 打开蓝蘑云用户管理后台,点击注册新用户


  1. 登录蓝蘑云用户管理后台,用刚注册的手机号码和密码登录管理后台

第二步:服务端创建应用AppID

  1. 点击创建新项目按钮,在弹出的对话框输入项目名称,点击立即创建;

  2. 获取APPID替换到项目中;
  3. 点击统计页面查看服务使用量;

收费标准

当前蓝蘑云提供1个月免费测试对接时间,让客户有充足时间对接测试,如果测试对接满意,需要联系商务开通正式服务商用,点击管理后台联系我们,可以联系到技术和商务;具体收费标准请查看官方标准,大客户都有优惠;
如您在对接中有任何其他问题需要技术咨询,可以加入我们的技术交流QQ群:701150764,或者直接联系我们商务,提供1对1技术支持;

继续阅读 »

概述:

maple-rtc 为蓝蘑云推出的直播&实时音视频系统,包括了直播,实时音频,视频,变声,美颜等功能,适用于娱乐,游戏,教育等实时场景中;Maple-RTC支持快速私有化部署,一键部署上线。

第一步:开通蓝蘑云服务

  1. 打开蓝蘑云用户管理后台,点击注册新用户


  1. 登录蓝蘑云用户管理后台,用刚注册的手机号码和密码登录管理后台

第二步:服务端创建应用AppID

  1. 点击创建新项目按钮,在弹出的对话框输入项目名称,点击立即创建;

  2. 获取APPID替换到项目中;
  3. 点击统计页面查看服务使用量;

收费标准

当前蓝蘑云提供1个月免费测试对接时间,让客户有充足时间对接测试,如果测试对接满意,需要联系商务开通正式服务商用,点击管理后台联系我们,可以联系到技术和商务;具体收费标准请查看官方标准,大客户都有优惠;
如您在对接中有任何其他问题需要技术咨询,可以加入我们的技术交流QQ群:701150764,或者直接联系我们商务,提供1对1技术支持;

收起阅读 »

解决uniApp转支付宝小程序button按钮无法触发授权成功回调

使用 支付宝 onGetAuthorize="onGetAuthorize" 和 @GetAuthorize="onGetAuthorize" 都不支持

解决办法 改用 @getAuthorize="onGetAuthorize" 如上图

继续阅读 »

使用 支付宝 onGetAuthorize="onGetAuthorize" 和 @GetAuthorize="onGetAuthorize" 都不支持

解决办法 改用 @getAuthorize="onGetAuthorize" 如上图

收起阅读 »

【屏幕适配问题】强烈反对uni-app的“屏幕适配” 实现方案

目前的 “屏幕适配” 实现方案非常糟糕 (https://uniapp.dcloud.net.cn/adapt),从我这边看,有种产品经理脑子被驴踢了的感觉。

这个功能连官方自己的案例显示都不正常,请看下图(或自己访问:https://static-7d133019-9a7e-474a-b7c2-c01751f00ca5.bspapp.com/#/ )

既然我 app 是为移动端设计的,那么每个页面也肯定是为移动端设计的,在移动端能正常显示,就是最核心目标!

而目前搞 right window 这一套非常奇怪,只是首页能正常显示了,详细页无法正常显示。

而且,

不是所有app都是资讯类型!并不是所有app都是资讯类型!并不是所有app都是资讯类型!

如果是其它类型,大概率会造成交互上的混乱

其实大家的需求很简单,就是网页版直接默认一个宽度,居中, 就ok了。请不要搞些累赘的right window折腾开发者了

另外:用 iframe 是不ok的,因为我需要pc端可以单独访问某个页面

希望这个功能可以悬崖勒马,不要自己YY一套莫名其妙的方案,尽快改回正常的模式

继续阅读 »

目前的 “屏幕适配” 实现方案非常糟糕 (https://uniapp.dcloud.net.cn/adapt),从我这边看,有种产品经理脑子被驴踢了的感觉。

这个功能连官方自己的案例显示都不正常,请看下图(或自己访问:https://static-7d133019-9a7e-474a-b7c2-c01751f00ca5.bspapp.com/#/ )

既然我 app 是为移动端设计的,那么每个页面也肯定是为移动端设计的,在移动端能正常显示,就是最核心目标!

而目前搞 right window 这一套非常奇怪,只是首页能正常显示了,详细页无法正常显示。

而且,

不是所有app都是资讯类型!并不是所有app都是资讯类型!并不是所有app都是资讯类型!

如果是其它类型,大概率会造成交互上的混乱

其实大家的需求很简单,就是网页版直接默认一个宽度,居中, 就ok了。请不要搞些累赘的right window折腾开发者了

另外:用 iframe 是不ok的,因为我需要pc端可以单独访问某个页面

希望这个功能可以悬崖勒马,不要自己YY一套莫名其妙的方案,尽快改回正常的模式

收起阅读 »

nvue map 组件 polyline 更换箭头图标格式说明

map polyline

nvue 页面 map 组件是基于高德地图实现的,如果您想自定义 polyline 的 箭头图标(对应 arrowIconPath )请参考附件中提供的示例图片设计,该图片为高德官方示例图片,请按照此图片的尺寸切图。

注意事项:

  • 在image两边增加部分透明像素,可减轻绘制产生的锯齿;
  • 图片中的箭头方向向上;

效果图:

<img src="https://img.cdn.aliyun.dcloud.net.cn/nativedocs/nativeplugin/Iosimgs/IMG_7C59BC6C6C7F-1.jpeg" width="50%"/>

附件:

继续阅读 »

nvue 页面 map 组件是基于高德地图实现的,如果您想自定义 polyline 的 箭头图标(对应 arrowIconPath )请参考附件中提供的示例图片设计,该图片为高德官方示例图片,请按照此图片的尺寸切图。

注意事项:

  • 在image两边增加部分透明像素,可减轻绘制产生的锯齿;
  • 图片中的箭头方向向上;

效果图:

<img src="https://img.cdn.aliyun.dcloud.net.cn/nativedocs/nativeplugin/Iosimgs/IMG_7C59BC6C6C7F-1.jpeg" width="50%"/>

附件:

收起阅读 »

推送PLUS重磅发布,全方位提升推送消息转化率

unipush

推送PLUS1.0主要从内容智选、数据归因、广告补发三大维度发力,以【分组对比】、【后效分析】、【广告补发】等功能模块为抓手,全方位助力运营提升推送消息转化率

【分组对比】通过对各测试组的到达-展示-点击数据的监测分析,筛选出最优文案/人群,并支持实时及定时地按最优测试组补发剩余用户,提高通知消息点击率,助力运营提效。

【后效分析】从推送任务、日期、用户三大数据维度,提供清晰明了的数据报表,全面分析应用的推送转化、趋势及用户活跃情况,并提供消息从下发-到达-展示-点击各个阶段的折损原因分析,针对不同参考指标灵活选择解决方案,提高推送消息的转化率。

【广告投放】针对推送无法触达的用户,使用广告投放的方式进行消息补发,提升用户点击数量,进一步提升DAU。

分组对比

分组测试功能支持在Android及iOS全平台,设置2-5组测试组,“对比通知文案”或“对比用户群体”,通过对各测试组的到达、展示、点击数据的监测分析,筛选出最优文案/人群,并支持实时及定时地按最优测试组补发剩余用户,提高通知消息点击率,助力运营提效。


分组对比详情可见:https://ask.dcloud.net.cn/article/37762

后效分析

后效分析,从推送任务、日期、用户三大数据维度,提供清晰明了的数据报表,全面分析应用的推送转化、趋势及用户活跃情况,并提供消息从下发-到达-展示-点击各个阶段的折损原因分析,针对不同参考指标灵活选择解决方案,提高推送消息的转化率。主要分为【数据报表】【折损原因分析】【大盘分析】三个模块。

【数据报表】个推数据报表主要分为3个模块:推送数据、日推送数、用户数据,从推送任务、日期、用户三大数据维度,全面分析应用的推送转化、趋势及用户活跃情况;更有关闭通知率、卸载用户数等特色数据分析。

【折损原因分析】针对单个推送任务,提供消息从下发-到达-展示-点击各阶段,消息未成功触达的折损原因分析,比如:卸载、关闭通知、推送超限、参数超限、参数无效等。快速诊断定位折损原因,针对性解决问题。

【大盘分析】针对单个推送任务,提供每个任务的消息到达率和点击率,与应用自身的平均值及个推大盘的均值做比较,高效评估该推送任务的转化水平,调整推送运营策略。


完整报表使用说明,详情可见:http://docs.getui.com/report/

广告投放

针对推送无法触达的用户,使用广告投放的方式进行消息补发,提升用户点击数量,进一步提升DAU。



开通此功能请联系:lieg@getui.com

继续阅读 »

推送PLUS1.0主要从内容智选、数据归因、广告补发三大维度发力,以【分组对比】、【后效分析】、【广告补发】等功能模块为抓手,全方位助力运营提升推送消息转化率

【分组对比】通过对各测试组的到达-展示-点击数据的监测分析,筛选出最优文案/人群,并支持实时及定时地按最优测试组补发剩余用户,提高通知消息点击率,助力运营提效。

【后效分析】从推送任务、日期、用户三大数据维度,提供清晰明了的数据报表,全面分析应用的推送转化、趋势及用户活跃情况,并提供消息从下发-到达-展示-点击各个阶段的折损原因分析,针对不同参考指标灵活选择解决方案,提高推送消息的转化率。

【广告投放】针对推送无法触达的用户,使用广告投放的方式进行消息补发,提升用户点击数量,进一步提升DAU。

分组对比

分组测试功能支持在Android及iOS全平台,设置2-5组测试组,“对比通知文案”或“对比用户群体”,通过对各测试组的到达、展示、点击数据的监测分析,筛选出最优文案/人群,并支持实时及定时地按最优测试组补发剩余用户,提高通知消息点击率,助力运营提效。


分组对比详情可见:https://ask.dcloud.net.cn/article/37762

后效分析

后效分析,从推送任务、日期、用户三大数据维度,提供清晰明了的数据报表,全面分析应用的推送转化、趋势及用户活跃情况,并提供消息从下发-到达-展示-点击各个阶段的折损原因分析,针对不同参考指标灵活选择解决方案,提高推送消息的转化率。主要分为【数据报表】【折损原因分析】【大盘分析】三个模块。

【数据报表】个推数据报表主要分为3个模块:推送数据、日推送数、用户数据,从推送任务、日期、用户三大数据维度,全面分析应用的推送转化、趋势及用户活跃情况;更有关闭通知率、卸载用户数等特色数据分析。

【折损原因分析】针对单个推送任务,提供消息从下发-到达-展示-点击各阶段,消息未成功触达的折损原因分析,比如:卸载、关闭通知、推送超限、参数超限、参数无效等。快速诊断定位折损原因,针对性解决问题。

【大盘分析】针对单个推送任务,提供每个任务的消息到达率和点击率,与应用自身的平均值及个推大盘的均值做比较,高效评估该推送任务的转化水平,调整推送运营策略。


完整报表使用说明,详情可见:http://docs.getui.com/report/

广告投放

针对推送无法触达的用户,使用广告投放的方式进行消息补发,提升用户点击数量,进一步提升DAU。



开通此功能请联系:lieg@getui.com

收起阅读 »

插件源码授权版购买流程

插件源码授权版购买流程 插件市场

插件源码授权版购买流程

购买,购买时需要确认基本信息


如果未经过e签宝认证则点击确认生成e签宝实名认证链接,跳转去e签宝实名认证

认证完成后,生成电子协议

点击跳转到e签宝签署电子协议
签署完成后

等待插件作者签署电子协议

协议签署完成,购买者会收到e签宝 短信/邮件 签署完成通知
用户可以在我购买的插件订单-未完成订单-待付款看到该订单或者直接打开该插件地址进行支付购买

购买完成,下载/导入HX

什么是e签宝

点击查看e签宝介绍

e签宝实名认证流程

点击查看e签宝实名认证流程

e签宝电子协议签署流程

点击查看e签宝电子协议签署流程

继续阅读 »

插件源码授权版购买流程

购买,购买时需要确认基本信息


如果未经过e签宝认证则点击确认生成e签宝实名认证链接,跳转去e签宝实名认证

认证完成后,生成电子协议

点击跳转到e签宝签署电子协议
签署完成后

等待插件作者签署电子协议

协议签署完成,购买者会收到e签宝 短信/邮件 签署完成通知
用户可以在我购买的插件订单-未完成订单-待付款看到该订单或者直接打开该插件地址进行支付购买

购买完成,下载/导入HX

什么是e签宝

点击查看e签宝介绍

e签宝实名认证流程

点击查看e签宝实名认证流程

e签宝电子协议签署流程

点击查看e签宝电子协议签署流程

收起阅读 »

数据修改页面不刷新问题记录

双向绑定 uniapp

一般来说页面和数据是双向绑定的,数据改变页面就会改变,可是有时候页面数据改变后,APP上页面不刷新,但微信小程序开发工具上又是可以的,一般这种情况是在数组使用时遇到的,记录几个遇到的情况和解决办法:
一、数组值修改,页面样式不刷新。解决:尝试用this.$set()方法,里面三个参数,第一个传这个数组,第二个传要修改的那项的下标,第三个传修改后的那项内容。下面会根据数组中的state状态加载不同的样式:

this.model.answer[j].state = !this.model.answer[j].state;  
this.$set(this.model.answer, j, this.model.answer[j])  
//页面根据变量加载不同样式  
<view  :class="item.state?'answer_yes':'answer_no'">{{item.name}}</view>

二、有一次我用this.$set()方法,数据改变后页面上的样式任然不刷新,奇怪的是,另一个页面一模一样的代码,刷新又正常,代码同上。询问了一圈,有老铁告诉我可能是数据太深了,然后我试着将answer数据从model中提取出来,新建一个数组来绑定页面:

this.model.answer[j].state = !this.model.answer[j].state;  
this.$set(this.model.answer, j, this.model.answer[j])  
//在上面的基础上添加下面这种操作,把页面上绑定的数组换成current_answer,测试时把上面一句注释竟然又失效了   
this.current_answer = this.model.answer

最后就正常了,坑啊。。。。
三、还有一种情况是定义的全局变量,如果页面绑定的是定义在其他文件下的全局变量,变量修改的时候,页面也不会刷新,这种情况就在当前页面再定义一个变量,这个变量在页面加载的时候接收全局变量的值,然后页面绑定这个变量就好了。

继续阅读 »

一般来说页面和数据是双向绑定的,数据改变页面就会改变,可是有时候页面数据改变后,APP上页面不刷新,但微信小程序开发工具上又是可以的,一般这种情况是在数组使用时遇到的,记录几个遇到的情况和解决办法:
一、数组值修改,页面样式不刷新。解决:尝试用this.$set()方法,里面三个参数,第一个传这个数组,第二个传要修改的那项的下标,第三个传修改后的那项内容。下面会根据数组中的state状态加载不同的样式:

this.model.answer[j].state = !this.model.answer[j].state;  
this.$set(this.model.answer, j, this.model.answer[j])  
//页面根据变量加载不同样式  
<view  :class="item.state?'answer_yes':'answer_no'">{{item.name}}</view>

二、有一次我用this.$set()方法,数据改变后页面上的样式任然不刷新,奇怪的是,另一个页面一模一样的代码,刷新又正常,代码同上。询问了一圈,有老铁告诉我可能是数据太深了,然后我试着将answer数据从model中提取出来,新建一个数组来绑定页面:

this.model.answer[j].state = !this.model.answer[j].state;  
this.$set(this.model.answer, j, this.model.answer[j])  
//在上面的基础上添加下面这种操作,把页面上绑定的数组换成current_answer,测试时把上面一句注释竟然又失效了   
this.current_answer = this.model.answer

最后就正常了,坑啊。。。。
三、还有一种情况是定义的全局变量,如果页面绑定的是定义在其他文件下的全局变量,变量修改的时候,页面也不会刷新,这种情况就在当前页面再定义一个变量,这个变量在页面加载的时候接收全局变量的值,然后页面绑定这个变量就好了。

收起阅读 »

本应用无法独立运行,需要与hbuilderX 搭配使用问题之一(使用SD卡)

uniapp 真机调试
  • uni-app项目使用荣耀手机(本人是荣耀20)真机调试时,出现app运行时显示“本应用无法独立运行,需要与hbuilderX 搭配使用”,是因为将存储的默认存储位置设置为SanDisk存储卡引起的。解决方法是将手机默认存储位置设置为内部存储即可。感觉应该是HBuilderX存在的BUG,希望官方对此类问题进行测试并解决。
  • 解决此问题时查询了很多类似的帖子,大概总结了一下,主要存在目录或文件名存在中文或者修改了存储位置引起,大家稍加注意应该可以解决,如还有其他情况请大家回复收集。
  • 仅供大家参考。
继续阅读 »
  • uni-app项目使用荣耀手机(本人是荣耀20)真机调试时,出现app运行时显示“本应用无法独立运行,需要与hbuilderX 搭配使用”,是因为将存储的默认存储位置设置为SanDisk存储卡引起的。解决方法是将手机默认存储位置设置为内部存储即可。感觉应该是HBuilderX存在的BUG,希望官方对此类问题进行测试并解决。
  • 解决此问题时查询了很多类似的帖子,大概总结了一下,主要存在目录或文件名存在中文或者修改了存储位置引起,大家稍加注意应该可以解决,如还有其他情况请大家回复收集。
  • 仅供大家参考。
收起阅读 »

nfc读取加密扇区

NFC

// 包路径
const package_NdefRecord = 'android.nfc.NdefRecord';
const package_NdefMessage = 'android.nfc.NdefMessage';
const package_TECH_DISCOVERED = 'android.nfc.action.TECH_DISCOVERED';
const package_Intent = 'android.content.Intent';
const package_Activity = 'android.app.Activity';
const package_PendingIntent = 'android.app.PendingIntent';
const package_IntentFilter = 'android.content.IntentFilter';
const package_NfcAdapter = 'android.nfc.NfcAdapter';
const package_Ndef = 'android.nfc.tech.Ndef';
const package_NdefFormatable = 'android.nfc.tech.NdefFormatable';
const package_Parcelable = 'android.os.Parcelable';
const package_String = 'java.lang.String';

let NfcAdapter;
let NdefRecord;
let NdefMessage;
let readyWriteData = false;
let readyRead = false;
let noNFC = false;
let techListsArray = [
["android.nfc.tech.IsoDep"],
["android.nfc.tech.NfcA"],
["android.nfc.tech.NfcB"],
["android.nfc.tech.NfcF"],
["android.nfc.tech.Ndef"],
["android.nfc.tech.NfcV"],
["android.nfc.tech.NdefFormatable"],
["android.nfc.tech.MifareClassic"],
["android.nfc.tech.MifareUltralight"]
];
// 要写入的数据
let text = '{id:123,name:nfc,stie:cssmini.com}';
let readResult = '';

export default {
listenNFCStatus: function() {
let that = this;
try {
let main = plus.android.runtimeMainActivity();
let Intent = plus.android.importClass('android.content.Intent');
let Activity = plus.android.importClass('android.app.Activity');
let PendingIntent = plus.android.importClass('android.app.PendingIntent');
let IntentFilter = plus.android.importClass('android.content.IntentFilter');
NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
let nfcAdapter = NfcAdapter.getDefaultAdapter(main);

        if (nfcAdapter == null) {  
            uni.showToast({  
                title: '设备不支持NFC!',  
                icon: 'none'  
            })  
            noNFC = true;  
            return;  
        }  

        if (!nfcAdapter.isEnabled()) {  
            uni.showToast({  
                title: '请在系统设置中先启用NFC功能!',  
                icon: 'none'  
            });  
            noNFC = true;  
            return;  
        } else {  
            noNFC = false;  
        }  

        let intent = new Intent(main, main.getClass());  
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
        let pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);  
        let ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");  
        ndef.addDataType("*/*");  
        let intentFiltersArray = [ndef];  

        plus.globalEvent.addEventListener('newintent', function() {  
            console.log('newintent running');  
            // 监听 NFC  
            setTimeout(that.nfcRuning(), 1000);  
        });  
        plus.globalEvent.addEventListener('pause', function(e) {  
            console.log('pause running');  
            if (nfcAdapter) {  
                //关闭前台调度系统  
                //恢复默认状态  
                nfcAdapter.disableForegroundDispatch(main);  
            }  
        });  
        plus.globalEvent.addEventListener('resume', function(e) {  
            console.log('resume running');  
            if (nfcAdapter) {  
                //开启前台调度系统  
                nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
            }  
        });  
        nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
    } catch (e) {  
        console.error(e);  
    }  
},  
nfcRuning: function() {  
    NdefRecord = plus.android.importClass("android.nfc.NdefRecord");  
    NdefMessage = plus.android.importClass("android.nfc.NdefMessage");  
    let main = plus.android.runtimeMainActivity();  
    let intent = main.getIntent();  
    let that = this;  

    console.log("action type:" + intent.getAction());  

    if (package_TECH_DISCOVERED == intent.getAction()) {  
        console.log("readyWriteData=" + readyWriteData + " readyRead=" + readyRead)  
        if (readyWriteData) {  
            that.write(intent);  
            readyWriteData = false;  
        } else if (readyRead) {  

            that.read(intent);  
            readyRead = false;  
        }  
    }  
},  
write(intent) {  
    try {  
        toast('请勿移开标签 正在写入...');  
        console.log("text=" + text);  

        let textBytes = plus.android.invoke(text, "getBytes");  
        // image/jpeg text/plain    
        let textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,  
            plus.android.invoke("text/plain", "getBytes"),  
            plus.android.invoke("", "getBytes"), textBytes);  
        let message = new NdefMessage([textRecord]);  
        let Ndef = plus.android.importClass('android.nfc.tech.Ndef');  
        let NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
        let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
        let ndef = Ndef.get(tag);  
        if (ndef != null) {  
            // 待写入的数据长度  
            let size = message.toByteArray().length;  
            ndef.connect();  
            if (!ndef.isWritable()) {  
                toast('tag不允许写入!');  
                return;  
            }  
            if (ndef.getMaxSize() < size) {  
                toast('文件大小超出容量!');  
                return;  
            }  
            ndef.writeNdefMessage(message);  
            toast('写入数据成功!');  
            return;  
        } else {  
            let format = NdefFormatable.get(tag);  
            if (format != null) {  
                try {  
                    format.connect();  
                    format.format(message);  
                    toast('格式化tag并且写入message');  
                    return;  
                } catch (e) {  
                    toast('格式化tag失败.');  
                    return;  
                }  
            } else {  
                toast('Tag不支持NDEF');  
                return;  
            }  
        }  
    } catch (e) {  
        toast('写入失败');  
        console.log("error=" + e);  
    }  

},  
read(intent) {  
    this.getData(intent);  
},  
byteArrayToHexString: function(inarray) { // converts byte arrays to string    
    let i, j, inn;  
    let hex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];  
    let out = "";  

    for (j = 0; j < inarray.length; ++j) {  
        if(inarray[j]==0) continue;  
        inn = inarray[j] & 0xff;  
        i = (inn >>> 4) & 0x0f;  
        out += hex[i];  
        i = inn & 0x0f;  
        out += hex[i];  
    }  
    return out;  
},  
writeData: function() {  
    if (noNFC) {  
        toast('请检查设备是否支持并开启 NFC 功能!');  
        return;  
    }  
    // 监听事件,触发条件  
    readyWriteData = true;  
    toast('请将NFC标签靠近!');  
},  
readData: function() {  
    if (noNFC) {  
        toast('请检查设备是否支持并开启 NFC 功能!');  
        return;  
    }  
    // 监听事件,触发条件  
    readyRead = true;  
    toast('请将NFC标签靠近!');  

},  
getData: function(intent) {  
    var sector = 1;  
    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
    let mc = plus.android.importClass('android.nfc.tech.MifareClassic');  
    let mfc = mc.get(tag);  
    console.log('mfc', mfc)  
    mfc.connect();  
    var cmdBytes = [0x6A, 0x69, 0x61, 0x6A, 0x75, 0x6E]  
    console.log('mfc', cmdBytes)  
    var auth = mfc.authenticateSectorWithKeyA(sector, cmdBytes)  

    console.log('auth', auth);  
    if (!auth) return;  
    try {  
        var tmpRet,result;  
        for (var i = 0; i < 3; i++) {  
            tmpRet = mfc.readBlock(sector * 4 + i);  
            result+=this.hexCharCodeToStr(this.byteArrayToHexString(tmpRet))  
        }  

        console.log('result',result);  
    } catch (e) {  
        this.ICERROR = e.message;  
        console.error(e);  
    } finally {  
        mfc.close();  
    }  
},  
//Key处理函数    
HexStringToByteArray: function(instr) {  
    var hexA = new Array();  
    var pos = 0;  
    var len = instr.length / 2;  
    for (var i = 0; i < len; i++) {  
        var s = instr.substr(pos, 2);  
        var v = parseInt(s, 16);  
        if (v >= 128)  
            v = v - 256;  
        hexA.push(v);  
        pos += 2;  
    }  
    return hexA;  
},  
hexCharCodeToStr: function(hexCharCodeStr) {  
    var trimedStr = hexCharCodeStr.trim();  
    var rawStr =  
        trimedStr.substr(0, 2).toLowerCase() === "0x" ?  
        trimedStr.substr(2) :  
        trimedStr;  
    var len = rawStr.length;  
    if (len % 2 !== 0) {  
        alert("Illegal Format ASCII Code!");  
        return "";  
    }  
    var curCharCode;  
    var resultStr = [];  
    for (var i = 0; i < len; i = i + 2) {  
        curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value  
        resultStr.push(String.fromCharCode(curCharCode));  
    }  
    return resultStr.join("");  
}  

}

function toast(content) {
uni.showToast({
title: content,
icon: 'none'
})
}

继续阅读 »

// 包路径
const package_NdefRecord = 'android.nfc.NdefRecord';
const package_NdefMessage = 'android.nfc.NdefMessage';
const package_TECH_DISCOVERED = 'android.nfc.action.TECH_DISCOVERED';
const package_Intent = 'android.content.Intent';
const package_Activity = 'android.app.Activity';
const package_PendingIntent = 'android.app.PendingIntent';
const package_IntentFilter = 'android.content.IntentFilter';
const package_NfcAdapter = 'android.nfc.NfcAdapter';
const package_Ndef = 'android.nfc.tech.Ndef';
const package_NdefFormatable = 'android.nfc.tech.NdefFormatable';
const package_Parcelable = 'android.os.Parcelable';
const package_String = 'java.lang.String';

let NfcAdapter;
let NdefRecord;
let NdefMessage;
let readyWriteData = false;
let readyRead = false;
let noNFC = false;
let techListsArray = [
["android.nfc.tech.IsoDep"],
["android.nfc.tech.NfcA"],
["android.nfc.tech.NfcB"],
["android.nfc.tech.NfcF"],
["android.nfc.tech.Ndef"],
["android.nfc.tech.NfcV"],
["android.nfc.tech.NdefFormatable"],
["android.nfc.tech.MifareClassic"],
["android.nfc.tech.MifareUltralight"]
];
// 要写入的数据
let text = '{id:123,name:nfc,stie:cssmini.com}';
let readResult = '';

export default {
listenNFCStatus: function() {
let that = this;
try {
let main = plus.android.runtimeMainActivity();
let Intent = plus.android.importClass('android.content.Intent');
let Activity = plus.android.importClass('android.app.Activity');
let PendingIntent = plus.android.importClass('android.app.PendingIntent');
let IntentFilter = plus.android.importClass('android.content.IntentFilter');
NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
let nfcAdapter = NfcAdapter.getDefaultAdapter(main);

        if (nfcAdapter == null) {  
            uni.showToast({  
                title: '设备不支持NFC!',  
                icon: 'none'  
            })  
            noNFC = true;  
            return;  
        }  

        if (!nfcAdapter.isEnabled()) {  
            uni.showToast({  
                title: '请在系统设置中先启用NFC功能!',  
                icon: 'none'  
            });  
            noNFC = true;  
            return;  
        } else {  
            noNFC = false;  
        }  

        let intent = new Intent(main, main.getClass());  
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
        let pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);  
        let ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");  
        ndef.addDataType("*/*");  
        let intentFiltersArray = [ndef];  

        plus.globalEvent.addEventListener('newintent', function() {  
            console.log('newintent running');  
            // 监听 NFC  
            setTimeout(that.nfcRuning(), 1000);  
        });  
        plus.globalEvent.addEventListener('pause', function(e) {  
            console.log('pause running');  
            if (nfcAdapter) {  
                //关闭前台调度系统  
                //恢复默认状态  
                nfcAdapter.disableForegroundDispatch(main);  
            }  
        });  
        plus.globalEvent.addEventListener('resume', function(e) {  
            console.log('resume running');  
            if (nfcAdapter) {  
                //开启前台调度系统  
                nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
            }  
        });  
        nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
    } catch (e) {  
        console.error(e);  
    }  
},  
nfcRuning: function() {  
    NdefRecord = plus.android.importClass("android.nfc.NdefRecord");  
    NdefMessage = plus.android.importClass("android.nfc.NdefMessage");  
    let main = plus.android.runtimeMainActivity();  
    let intent = main.getIntent();  
    let that = this;  

    console.log("action type:" + intent.getAction());  

    if (package_TECH_DISCOVERED == intent.getAction()) {  
        console.log("readyWriteData=" + readyWriteData + " readyRead=" + readyRead)  
        if (readyWriteData) {  
            that.write(intent);  
            readyWriteData = false;  
        } else if (readyRead) {  

            that.read(intent);  
            readyRead = false;  
        }  
    }  
},  
write(intent) {  
    try {  
        toast('请勿移开标签 正在写入...');  
        console.log("text=" + text);  

        let textBytes = plus.android.invoke(text, "getBytes");  
        // image/jpeg text/plain    
        let textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,  
            plus.android.invoke("text/plain", "getBytes"),  
            plus.android.invoke("", "getBytes"), textBytes);  
        let message = new NdefMessage([textRecord]);  
        let Ndef = plus.android.importClass('android.nfc.tech.Ndef');  
        let NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
        let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
        let ndef = Ndef.get(tag);  
        if (ndef != null) {  
            // 待写入的数据长度  
            let size = message.toByteArray().length;  
            ndef.connect();  
            if (!ndef.isWritable()) {  
                toast('tag不允许写入!');  
                return;  
            }  
            if (ndef.getMaxSize() < size) {  
                toast('文件大小超出容量!');  
                return;  
            }  
            ndef.writeNdefMessage(message);  
            toast('写入数据成功!');  
            return;  
        } else {  
            let format = NdefFormatable.get(tag);  
            if (format != null) {  
                try {  
                    format.connect();  
                    format.format(message);  
                    toast('格式化tag并且写入message');  
                    return;  
                } catch (e) {  
                    toast('格式化tag失败.');  
                    return;  
                }  
            } else {  
                toast('Tag不支持NDEF');  
                return;  
            }  
        }  
    } catch (e) {  
        toast('写入失败');  
        console.log("error=" + e);  
    }  

},  
read(intent) {  
    this.getData(intent);  
},  
byteArrayToHexString: function(inarray) { // converts byte arrays to string    
    let i, j, inn;  
    let hex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];  
    let out = "";  

    for (j = 0; j < inarray.length; ++j) {  
        if(inarray[j]==0) continue;  
        inn = inarray[j] & 0xff;  
        i = (inn >>> 4) & 0x0f;  
        out += hex[i];  
        i = inn & 0x0f;  
        out += hex[i];  
    }  
    return out;  
},  
writeData: function() {  
    if (noNFC) {  
        toast('请检查设备是否支持并开启 NFC 功能!');  
        return;  
    }  
    // 监听事件,触发条件  
    readyWriteData = true;  
    toast('请将NFC标签靠近!');  
},  
readData: function() {  
    if (noNFC) {  
        toast('请检查设备是否支持并开启 NFC 功能!');  
        return;  
    }  
    // 监听事件,触发条件  
    readyRead = true;  
    toast('请将NFC标签靠近!');  

},  
getData: function(intent) {  
    var sector = 1;  
    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
    let mc = plus.android.importClass('android.nfc.tech.MifareClassic');  
    let mfc = mc.get(tag);  
    console.log('mfc', mfc)  
    mfc.connect();  
    var cmdBytes = [0x6A, 0x69, 0x61, 0x6A, 0x75, 0x6E]  
    console.log('mfc', cmdBytes)  
    var auth = mfc.authenticateSectorWithKeyA(sector, cmdBytes)  

    console.log('auth', auth);  
    if (!auth) return;  
    try {  
        var tmpRet,result;  
        for (var i = 0; i < 3; i++) {  
            tmpRet = mfc.readBlock(sector * 4 + i);  
            result+=this.hexCharCodeToStr(this.byteArrayToHexString(tmpRet))  
        }  

        console.log('result',result);  
    } catch (e) {  
        this.ICERROR = e.message;  
        console.error(e);  
    } finally {  
        mfc.close();  
    }  
},  
//Key处理函数    
HexStringToByteArray: function(instr) {  
    var hexA = new Array();  
    var pos = 0;  
    var len = instr.length / 2;  
    for (var i = 0; i < len; i++) {  
        var s = instr.substr(pos, 2);  
        var v = parseInt(s, 16);  
        if (v >= 128)  
            v = v - 256;  
        hexA.push(v);  
        pos += 2;  
    }  
    return hexA;  
},  
hexCharCodeToStr: function(hexCharCodeStr) {  
    var trimedStr = hexCharCodeStr.trim();  
    var rawStr =  
        trimedStr.substr(0, 2).toLowerCase() === "0x" ?  
        trimedStr.substr(2) :  
        trimedStr;  
    var len = rawStr.length;  
    if (len % 2 !== 0) {  
        alert("Illegal Format ASCII Code!");  
        return "";  
    }  
    var curCharCode;  
    var resultStr = [];  
    for (var i = 0; i < len; i = i + 2) {  
        curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value  
        resultStr.push(String.fromCharCode(curCharCode));  
    }  
    return resultStr.join("");  
}  

}

function toast(content) {
uni.showToast({
title: content,
icon: 'none'
})
}

收起阅读 »

plus 解决uni-app播放多音频背景音乐

音乐播放

plus 解决uni-app播放多音频背景音乐

播放音频文件


let audioPlayer = null;  

// #ifdef APP-PLUS  
// 背景音乐文件  
let path = plus.io.convertLocalFileSystemURL("_www/static/audio/background_music.mp3");  
if (plus.os.name == 'Android') {  
    let MediaPlayer = plus.android.importClass("android.media.MediaPlayer");  
    audioPlayer = new MediaPlayer()  
    audioPlayer.setDataSource(path); //指定音频文件路径  
    audioPlayer.setLooping(true); //设置为循环播放  
    audioPlayer.prepare(); //初始化播放器MediaPlayer  
    audioPlayer.start();  
    // 获取音乐的总时长  
    console.log(audioPlayer.getDuration());  
}  
if (plus.os.name == "iOS") {  
    let NSData = plus.ios.importClass("NSData");  
    let AVAudioPlayer = plus.ios.importClass("AVAudioPlayer");  
    let pathFileData = NSData.dataWithContentsOfFile(path);  
    audioPlayer = new AVAudioPlayer();  
    audioPlayer.initWithDataerror(pathFileData, null);  
    audioPlayer.setNumberOfLoops(-1); //-1:无限循环   
    audioPlayer.prepareToPlay(); //初始化播放器  
    audioPlayer.play();  
    // 获取音乐的总时长  
    console.log(audioPlayer.duration());  
}  
// #endif

调节系统媒体音量


let AudioManager = null;  
let audioManager = null;  

/// 获取系统音量控制  
// #ifdef APP-PLUS  
if (plus.os.name == 'Android') {  
    let context = plus.android.importClass("android.content.Context");  
    let main = plus.android.runtimeMainActivity();  
    AudioManager = plus.android.importClass("android.media.AudioManager");  
    audioManager = main.getSystemService(context.AUDIO_SERVICE);  
    // 调节是否显示调节ui  
    // audioManager.adjustStreamVolume (AudioManager.STREAM_MUSIC , AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI)  
    // 音量最大范围  
    let max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
    // 当前音量值  
    let current = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);  
    console.log(max, current);  
}  
if (plus.os.name == "iOS") {  
    // 暂无查找  
}  
// #endif  

// 设置音量值  
// #ifdef APP-PLUS  
if (plus.os.name == 'Android') {  
    audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 89, 0); // 89为音量值  
}  
if (plus.os.name == "iOS") {  
    // 暂无查找  
}  
// #endif  
继续阅读 »

plus 解决uni-app播放多音频背景音乐

播放音频文件


let audioPlayer = null;  

// #ifdef APP-PLUS  
// 背景音乐文件  
let path = plus.io.convertLocalFileSystemURL("_www/static/audio/background_music.mp3");  
if (plus.os.name == 'Android') {  
    let MediaPlayer = plus.android.importClass("android.media.MediaPlayer");  
    audioPlayer = new MediaPlayer()  
    audioPlayer.setDataSource(path); //指定音频文件路径  
    audioPlayer.setLooping(true); //设置为循环播放  
    audioPlayer.prepare(); //初始化播放器MediaPlayer  
    audioPlayer.start();  
    // 获取音乐的总时长  
    console.log(audioPlayer.getDuration());  
}  
if (plus.os.name == "iOS") {  
    let NSData = plus.ios.importClass("NSData");  
    let AVAudioPlayer = plus.ios.importClass("AVAudioPlayer");  
    let pathFileData = NSData.dataWithContentsOfFile(path);  
    audioPlayer = new AVAudioPlayer();  
    audioPlayer.initWithDataerror(pathFileData, null);  
    audioPlayer.setNumberOfLoops(-1); //-1:无限循环   
    audioPlayer.prepareToPlay(); //初始化播放器  
    audioPlayer.play();  
    // 获取音乐的总时长  
    console.log(audioPlayer.duration());  
}  
// #endif

调节系统媒体音量


let AudioManager = null;  
let audioManager = null;  

/// 获取系统音量控制  
// #ifdef APP-PLUS  
if (plus.os.name == 'Android') {  
    let context = plus.android.importClass("android.content.Context");  
    let main = plus.android.runtimeMainActivity();  
    AudioManager = plus.android.importClass("android.media.AudioManager");  
    audioManager = main.getSystemService(context.AUDIO_SERVICE);  
    // 调节是否显示调节ui  
    // audioManager.adjustStreamVolume (AudioManager.STREAM_MUSIC , AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI)  
    // 音量最大范围  
    let max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
    // 当前音量值  
    let current = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);  
    console.log(max, current);  
}  
if (plus.os.name == "iOS") {  
    // 暂无查找  
}  
// #endif  

// 设置音量值  
// #ifdef APP-PLUS  
if (plus.os.name == 'Android') {  
    audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 89, 0); // 89为音量值  
}  
if (plus.os.name == "iOS") {  
    // 暂无查找  
}  
// #endif  
收起阅读 »