
uniapp MIUI全局自由窗口适配,uniapp悬浮小窗和分屏适配
uniapp MIUI全局自由窗口适配,uniapp悬浮小窗和分屏适配
uniapp 适配 MIUI 12的全局自由窗口和应用分屏适配
实例APP:微垠影视
Android平台API等级配置 - minSdkVersion&targetSdkVersion
4.自由窗口技术适配指南
MIUI的小窗是基于Android的多窗口Freeform方案实现的。
小窗目前主要问题是应用兼容性导致的一系列问题,内容显示不全、Touch事件不响应等等,其实根本原因是应用没有很好的支持、适配多窗口、多分辨率,如下是小窗适配的一些参考性适配指南。
应用声明是否支持自由窗口
如果您的应用以 API 级别 24 或更高级别为目标平台,那么您可以配置该应用的 activity 是否支持以及如何支持多窗口显示,自由窗口也是google多窗口的一种,所以goolge多窗口适配方案同样适用,可以在清单的或元素中设置此属性,以启用或停用多窗口显示:
android:resizeableActivity=[“true” | “false”]
如果将此属性设置为 true,则activity 能以分屏和自由窗口模式启动。如果将此属性设置为 false,则 activity 不支持多窗口模式。如果此值为 false,并且用户尝试在多窗口模式下启动 activity,则 activity 会全屏显示。
如果您的应用以 API 级别 24 为目标平台,但您未指定此属性的值,则其值默认设为 true。
uniapp 适配只需在manifest.json中》APP常用设置进行配置:Android平台API等级配置 - minSdkVersion&targetSdkVersion
24-30
实例APP:https://sj.miyin.fun
API等级与Android版本对应列表如下:
API等级 Android版本号
14 Android4.0
15 Android4.0.3
16 Android4.1.2
17 Android4.2.2
18 Android4.3.1
19 Android4.4.2
20 Android4.4W.2
21 Android5.0.1
22 Android5.1
24 Android7.0
25 Android7.1.1
26 Android8.0
27 Android8.1
28 Android9.0
29 Android10.0(Android Q)
30 Android11.0
效果:
uniapp MIUI全局自由窗口适配,uniapp悬浮小窗和分屏适配
uniapp 适配 MIUI 12的全局自由窗口和应用分屏适配
实例APP:微垠影视
Android平台API等级配置 - minSdkVersion&targetSdkVersion
4.自由窗口技术适配指南
MIUI的小窗是基于Android的多窗口Freeform方案实现的。
小窗目前主要问题是应用兼容性导致的一系列问题,内容显示不全、Touch事件不响应等等,其实根本原因是应用没有很好的支持、适配多窗口、多分辨率,如下是小窗适配的一些参考性适配指南。
应用声明是否支持自由窗口
如果您的应用以 API 级别 24 或更高级别为目标平台,那么您可以配置该应用的 activity 是否支持以及如何支持多窗口显示,自由窗口也是google多窗口的一种,所以goolge多窗口适配方案同样适用,可以在清单的或元素中设置此属性,以启用或停用多窗口显示:
android:resizeableActivity=[“true” | “false”]
如果将此属性设置为 true,则activity 能以分屏和自由窗口模式启动。如果将此属性设置为 false,则 activity 不支持多窗口模式。如果此值为 false,并且用户尝试在多窗口模式下启动 activity,则 activity 会全屏显示。
如果您的应用以 API 级别 24 为目标平台,但您未指定此属性的值,则其值默认设为 true。
uniapp 适配只需在manifest.json中》APP常用设置进行配置:Android平台API等级配置 - minSdkVersion&targetSdkVersion
24-30
实例APP:https://sj.miyin.fun
API等级与Android版本对应列表如下:
API等级 Android版本号
14 Android4.0
15 Android4.0.3
16 Android4.1.2
17 Android4.2.2
18 Android4.3.1
19 Android4.4.2
20 Android4.4W.2
21 Android5.0.1
22 Android5.1
24 Android7.0
25 Android7.1.1
26 Android8.0
27 Android8.1
28 Android9.0
29 Android10.0(Android Q)
30 Android11.0
效果:
收起阅读 »
匠心出品,跨平台前端组件库FirstUI 1.2.0正式发布
FirstUI(https://www.firstui.cn/)是基于uni-app开发的一款轻量、全面可靠的跨平台移动端组件库。包括框架、组件、模板、功能插件几个部分。FirstUI开发者、设计师不断精心打磨,持续发布新的组件、模板等新功能,力求为用户提供更高品质的产品,节约用户时间与成本。
一、FirstUI特性
● 多端支持。一套代码,多端适用,支持iOS(vue和Nvue)、Android(vue和Nvue)、微信小程序、支付宝小程序、QQ小程序、百度小程序、字节跳动小程序、H5平台
● 完善的组件。目前共规划118款,已上线70款,涵盖基础组件、表单组件、导航组件、布局组件、常用布局、扩展组件、操作反馈、数据组件、JS、图表、画布。
● 丰富实用的布局、模板。基于FirstUI提供的组件,针对常用场景、行业,提供丰富实用的布局和模板。
● 专属社区。我们打造了FirstU专属社区,用户可以在社区交流分享FirstUI的使用经验、提问。有其他组件、模板需求,也可以在社区中反馈。
二、FirstUI体系进展

三、扫码体验FirstUI
考虑快速预览,所以暂未上架App应用,后续待功能完善再进行上架。
四、开源版与商业版
FirstUI分为开源版与商业版,部分组件为商业版专属使用。
1、开源版
● github: https://github.com/FirstUI/FirstUI (欢迎star :-D)
● gitee: https://gitee.com/firstui/FirstUI (欢迎star :-D)
● 文档地址: https://doc.firstui.cn
2、VIP会员权益:
● 完整版源码
● 全部组件
● 物料商城享VIP折扣
● 专属会员群指导、答疑
● 新特性优先体验
● VIP专属文档
会员权益详情: https://www.firstui.cn/right
3、新版优惠
新版发布,优惠期内框架可5折¥150元购买(原价¥300元),2022年01月31日截止。购买框架产品即升级为VIP会员,享受VIP会员权益。
立即购买:https://www.firstui.cn/store/detail/1
FirstUI(https://www.firstui.cn/)是基于uni-app开发的一款轻量、全面可靠的跨平台移动端组件库。包括框架、组件、模板、功能插件几个部分。FirstUI开发者、设计师不断精心打磨,持续发布新的组件、模板等新功能,力求为用户提供更高品质的产品,节约用户时间与成本。
一、FirstUI特性
● 多端支持。一套代码,多端适用,支持iOS(vue和Nvue)、Android(vue和Nvue)、微信小程序、支付宝小程序、QQ小程序、百度小程序、字节跳动小程序、H5平台
● 完善的组件。目前共规划118款,已上线70款,涵盖基础组件、表单组件、导航组件、布局组件、常用布局、扩展组件、操作反馈、数据组件、JS、图表、画布。
● 丰富实用的布局、模板。基于FirstUI提供的组件,针对常用场景、行业,提供丰富实用的布局和模板。
● 专属社区。我们打造了FirstU专属社区,用户可以在社区交流分享FirstUI的使用经验、提问。有其他组件、模板需求,也可以在社区中反馈。
二、FirstUI体系进展
三、扫码体验FirstUI
考虑快速预览,所以暂未上架App应用,后续待功能完善再进行上架。
四、开源版与商业版
FirstUI分为开源版与商业版,部分组件为商业版专属使用。
1、开源版
● github: https://github.com/FirstUI/FirstUI (欢迎star :-D)
● gitee: https://gitee.com/firstui/FirstUI (欢迎star :-D)
● 文档地址: https://doc.firstui.cn
2、VIP会员权益:
● 完整版源码
● 全部组件
● 物料商城享VIP折扣
● 专属会员群指导、答疑
● 新特性优先体验
● VIP专属文档
会员权益详情: https://www.firstui.cn/right
3、新版优惠
新版发布,优惠期内框架可5折¥150元购买(原价¥300元),2022年01月31日截止。购买框架产品即升级为VIP会员,享受VIP会员权益。
立即购买:https://www.firstui.cn/store/detail/1

说真的。文档体验绝了
说真的。文档体验绝了,真的绝了。
我们用开源的东西本不该开口索要的,uni-app也算是你们的一个产品了。 你们也有商业模式,能否将文档好好整理一下, 文档体验简直不要太好
说真的。文档体验绝了,真的绝了。
我们用开源的东西本不该开口索要的,uni-app也算是你们的一个产品了。 你们也有商业模式,能否将文档好好整理一下, 文档体验简直不要太好

tag的监听事件方法。
代码渲染的titleNView 里的tag如何监听。代码如下。
假设你的tags里有一个子tag left 距离是30,宽度是130。
//那么就先定义监听区域
plus.webview.currentWebview().getTitleNView().setTouchEventRect({top:'0px',left:'30px',width:'130px',height:'100%'})
//创建监听。
plus.webview.currentWebview().getTitleNView().addEventListener("click",function(e){ })
注:setTouchEventRect 可以传数组。多个区域监听。
有问题欢迎留言,大家一起讨论。
代码渲染的titleNView 里的tag如何监听。代码如下。
假设你的tags里有一个子tag left 距离是30,宽度是130。
//那么就先定义监听区域
plus.webview.currentWebview().getTitleNView().setTouchEventRect({top:'0px',left:'30px',width:'130px',height:'100%'})
//创建监听。
plus.webview.currentWebview().getTitleNView().addEventListener("click",function(e){ })
注:setTouchEventRect 可以传数组。多个区域监听。
有问题欢迎留言,大家一起讨论。

uniapp直接跳转应用商店
// 跳转应用商店
export const jumpToAppMarket = (code) => {
// 可以根據文檔換成其他商店 https://www.jianshu.com/p/b544810beac3
const googlePlay = "com.android.vending";
if (plus.os.name == "Android") {
var Uri = plus.android.importClass("android.net.Uri");
var Intent = plus.android.importClass('android.content.Intent');
var main = plus.android.runtimeMainActivity();
var uri = Uri.parse("market://details?id=" + 包名);
var intent = new Intent(Intent.ACTION_VIEW, uri);
// 选择进入商店
intent.setPackage(googlePlay);
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK;
// 没有该商店应用
if (intent.resolveActivity(main.getPackageManager()) !== null) {
main.startActivity(intent);
} else {
// 跳转浏览器
let uri = Uri.parse("https://play.google.com/store/apps/details?id=" + 包名);
let intent = new Intent(Intent.ACTION_VIEW, uri);
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK;
intent.setPackage('com.android.browser');
main.startActivity(intent);
}
} else {
plus.runtime.openURL('itms-apps://itunes.apple.com/cn/app/id{appid}?mt=8');
}
}
// 跳转应用商店
export const jumpToAppMarket = (code) => {
// 可以根據文檔換成其他商店 https://www.jianshu.com/p/b544810beac3
const googlePlay = "com.android.vending";
if (plus.os.name == "Android") {
var Uri = plus.android.importClass("android.net.Uri");
var Intent = plus.android.importClass('android.content.Intent');
var main = plus.android.runtimeMainActivity();
var uri = Uri.parse("market://details?id=" + 包名);
var intent = new Intent(Intent.ACTION_VIEW, uri);
// 选择进入商店
intent.setPackage(googlePlay);
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK;
// 没有该商店应用
if (intent.resolveActivity(main.getPackageManager()) !== null) {
main.startActivity(intent);
} else {
// 跳转浏览器
let uri = Uri.parse("https://play.google.com/store/apps/details?id=" + 包名);
let intent = new Intent(Intent.ACTION_VIEW, uri);
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK;
intent.setPackage('com.android.browser');
main.startActivity(intent);
}
} else {
plus.runtime.openURL('itms-apps://itunes.apple.com/cn/app/id{appid}?mt=8');
}
}
收起阅读 »
基于uniapp打包生成app,并引入本地原生插件步骤和踩坑
看到社区很多同学对于uniapp和原生混合开发配置问题,就怎么引入原生本地插件并配置运行步骤详解
1.首先在你的文件夹下建nativeplugins目录,将本地开发的原生插件代码包按照格式放入
2.对nativeplugins目录下的pack.json进行配置 注意name和id要与目录名保持一致,class要安卓小伙伴给你,包名 类名
3.在manifest.json进行插件引入
第四步:点击运行到手机或模拟器,先制定基座,制作完成后在运行基座选择自定义基座,进行打包即可
看到社区很多同学对于uniapp和原生混合开发配置问题,就怎么引入原生本地插件并配置运行步骤详解
1.首先在你的文件夹下建nativeplugins目录,将本地开发的原生插件代码包按照格式放入
2.对nativeplugins目录下的pack.json进行配置 注意name和id要与目录名保持一致,class要安卓小伙伴给你,包名 类名
3.在manifest.json进行插件引入
第四步:点击运行到手机或模拟器,先制定基座,制作完成后在运行基座选择自定义基座,进行打包即可
收起阅读 »

录音支持暂停、继续、后台录音、息屏录音(ios、andorid)
录音支持暂停、继续、后台录音、息屏录音(ios、andorid) :https://ext.dcloud.net.cn/plugin?id=5849
录音支持暂停、继续、后台录音、息屏录音(ios、andorid) :https://ext.dcloud.net.cn/plugin?id=5849

强制安卓进入前台运行,完整代码及遇到的坑
最近突发奇想,想做一个给自己用的app,主要时做一些个人记录和强制停止无脑刷屏==。
在每次解锁手机或刷视频超过一定时间,后台就把自己开发的app进入前台,提醒自己的目标及可以做其他的事有什么。
网上的资料并不能完整的解决问题,然后就自己撸了一下代码。
todo 之后有空的话把这部分打包成一个uniapp的插件。
完整代码
Timer topTimer=null;
public void startTopTimer(){
stopTopTimer();
topTimer=new Timer();
TimerTask timerTask=new TimerTask() {
@Override
public void run() {
activityInTop();
}
};
topTimer.schedule(timerTask,0,500);
}
public void stopTopTimer(){
if(topTimer!=null){
topTimer.cancel();
topTimer=null;
}
}
public void activityInTop() {
/**获取ActivityManager*/
ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(ACTIVITY_SERVICE);
/**获得当前运行的task(任务)*/
int nowPosition=0;
List<ActivityManager.RunningTaskInfo> taskInfoList = activityManager.getRunningTasks(100);
for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) {
/**找到本应用的 task,并将它切换到前台*/
if (taskInfo.topActivity.getPackageName().equals(getApplicationContext().getPackageName())) {
if(nowPosition==0){
stopTopTimer();
return;
}
activityManager.moveTaskToFront(taskInfo.id, 0);
Log.d(TAG, "找到本应用的 task,并将它切换到前台");
return;
}
nowPosition++;
}
// 应用需要置顶且前台应用被关闭时,重新打开应用
Intent intent=getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
使用
startTopTimer();
碰到的坑
应用被关闭时,service需要拉起一个新的应用
// 应用需要置顶且前台应用被关闭时,重新打开应用
Intent intent=getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
moveTaskToFront需要在应用进入后台5-7s后执行
解决方案:执行moveTaskToFront方法后,判断是否成功。不成功每间隔500ms再执行一次,直到成功为止。
最近突发奇想,想做一个给自己用的app,主要时做一些个人记录和强制停止无脑刷屏==。
在每次解锁手机或刷视频超过一定时间,后台就把自己开发的app进入前台,提醒自己的目标及可以做其他的事有什么。
网上的资料并不能完整的解决问题,然后就自己撸了一下代码。
todo 之后有空的话把这部分打包成一个uniapp的插件。
完整代码
Timer topTimer=null;
public void startTopTimer(){
stopTopTimer();
topTimer=new Timer();
TimerTask timerTask=new TimerTask() {
@Override
public void run() {
activityInTop();
}
};
topTimer.schedule(timerTask,0,500);
}
public void stopTopTimer(){
if(topTimer!=null){
topTimer.cancel();
topTimer=null;
}
}
public void activityInTop() {
/**获取ActivityManager*/
ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(ACTIVITY_SERVICE);
/**获得当前运行的task(任务)*/
int nowPosition=0;
List<ActivityManager.RunningTaskInfo> taskInfoList = activityManager.getRunningTasks(100);
for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) {
/**找到本应用的 task,并将它切换到前台*/
if (taskInfo.topActivity.getPackageName().equals(getApplicationContext().getPackageName())) {
if(nowPosition==0){
stopTopTimer();
return;
}
activityManager.moveTaskToFront(taskInfo.id, 0);
Log.d(TAG, "找到本应用的 task,并将它切换到前台");
return;
}
nowPosition++;
}
// 应用需要置顶且前台应用被关闭时,重新打开应用
Intent intent=getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
使用
startTopTimer();
碰到的坑
应用被关闭时,service需要拉起一个新的应用
// 应用需要置顶且前台应用被关闭时,重新打开应用
Intent intent=getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
moveTaskToFront需要在应用进入后台5-7s后执行
解决方案:执行moveTaskToFront方法后,判断是否成功。不成功每间隔500ms再执行一次,直到成功为止。
收起阅读 »
Android 音乐通知栏Native.js版本!
代码
const androidNotifi = {
NotifyID: 237,
receiver:null,
NotifiService:null,
serv: null,
intent: null,
mNotificationBuild: null,
mediaBtn: null,
channelID : '1',
channelName : '音乐通知',
notifiImg:{},
getImgTemp: function(audioImage) {
return new Promise(resolve => {
if (this.notifiImg[encodeURIComponent(audioImage)]) {
return resolve(plus.io.convertLocalFileSystemURL(this.notifiImg[encodeURIComponent(audioImage)]));
}
if(!/^http/.test(audioImage)) {
this.notifiImg[encodeURIComponent(audioImage)] = audioImage ? audioImage : '_www/static/image/notifimusic.png';
return resolve(plus.io.convertLocalFileSystemURL(audioImage ? audioImage : '_www/static/image/notifimusic.png'));
}
uni.downloadFile({
url: audioImage,
complete: res => {
this.notifiImg[encodeURIComponent(audioImage)] = res.tempFilePath ? res.tempFilePath : '_www/static/image/notifimusic.png';
return resolve(plus.io.convertLocalFileSystemURL(res.tempFilePath ? res.tempFilePath : '_www/static/image/notifimusic.png'));
}
});
});
},
hideNotifi: function(server = false){
this.main&&this.receiver&&this.main.unregisterReceiver(this.receiver);
server&&this.serv&&this.serv.stopForeground&&this.serv.stopForeground(this.NotifyID, this.mNotificationBuild) ;
if (Number(plus.os.version.split('.')[0])>= 8){
this.NotifiService&&this.NotifiService.cancel&&this.NotifiService.cancel(this.channelID,this.NotifyID);
} else {
this.NotifiService&&this.NotifiService.cancel&&this.NotifiService.cancel(this.NotifyID);
}
this.receiver = null;
this.NotifiService = null;
this.serv = null;
this.intent = null;
this.mNotificationBuild = null;
// this.NotifiService&&this.NotifiService.cancelAll&&this.NotifiService.cancelAll();
this.mediaBtn ? this.mediaBtn.release() : ''; // 线控销毁
},
showNotifi:async function(param) {
if (uni.$_sko.systemInfo.platform != 'android') {
return;
}
try{
param = Object.assign({
title : '通知标题',
subTitle: '',
cont : '通知内容',
isPlay: true, // 媒体播放按钮
legIcon : plus.io.convertLocalFileSystemURL('_www/static/image/notifimusic.png'),
Ongoing : false, // 不可删除
},param);
this.main = this.main ? this.main : plus.android.runtimeMainActivity();
var Context = plus.android.importClass("android.content.Context");
var BitmapFactory = plus.android.importClass("android.graphics.BitmapFactory");
var NotificationManager = plus.android.importClass("android.app.NotificationManager");
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 androidR = plus.android.importClass("android.R");
this.NotifiService = this.NotifiService ? this.NotifiService : this.main.getSystemService(Context.NOTIFICATION_SERVICE);
this.intent = this.intent ? this.intent : new Intent(this.main, this.main.getClass());
var UNI_MEDIA_BROAD = this.main.getPackageName() + '.mediaBtn';
//PendingIntent.getActivity的第二个参数需要设置为随机数,否则多个通知时会导致前面的通知被后面的通知替换Extra的数据
var pendingIntent = PendingIntent.getActivity(this.main, 0, this.intent, PendingIntent.FLAG_CANCEL_CURRENT);
var firstVersionNumber = Number(plus.os.version.split('.')[0]);
var mNotification;
//判断当前系统版本在8.0及以上
if (firstVersionNumber >= 8){
if (this.NotifiService.getNotificationChannel() == null){
var NotificationChannel = plus.android.importClass('android.app.NotificationChannel');
var channel = new NotificationChannel(this.channelID, this.channelName, NotificationManager.IMPORTANCE_HIGH);
this.NotifiService.createNotificationChannel(channel);
plus.android.autoCollection(NotificationChannel);
}
param.callBack&&this.main.startForegroundService(this.intent);
mNotification = new Notification.Builder(this.main, this.channelID);
} else {
mNotification = new Notification.Builder(this.main);
param.callBack&&this.main.startService(this.intent);
}
if(param.callBack) {
mNotification.addAction(androidR.drawable.ic_media_previous, "prev", PendingIntent.getBroadcast(this.main, 0, new Intent().setAction(UNI_MEDIA_BROAD + '.prev'), PendingIntent.FLAG_CANCEL_CURRENT));
mNotification.addAction((param.isPlay ? androidR.drawable.ic_media_pause : androidR.drawable.ic_media_play), "play", PendingIntent.getBroadcast(this.main, 0, new Intent().setAction(UNI_MEDIA_BROAD + '.play'), PendingIntent.FLAG_CANCEL_CURRENT));
mNotification.addAction(androidR.drawable.ic_media_next, "next", PendingIntent.getBroadcast(this.main, 0, new Intent().setAction(UNI_MEDIA_BROAD + '.next'), PendingIntent.FLAG_CANCEL_CURRENT));
var mMediaStyle = new Notification.MediaStyle();
mMediaStyle.setShowActionsInCompactView(0, 1, 2);
mNotification.setStyle(mMediaStyle);
}
mNotification.setOngoing(param.Ongoing);
param.legIcon&&mNotification.setLargeIcon(BitmapFactory.decodeFile(await this.getImgTemp(param.legIcon)));
mNotification.setSmallIcon(param.callBack?androidR.drawable.stat_sys_headset:androidR.drawable.stat_notify_chat); //设置图标
mNotification.setContentTitle(param.title);//设置标题
mNotification.setContentText(param.cont); //设置内容
param.subTitle&&mNotification.setSubText(param.subTitle); //子内容暂时去掉
// mNotification.setAutoCancel(true); //设置点击消失
// mNotification.setShowWhen(true); //显示通知时间
mNotification.setTicker("PadInfo"); //弹出通知
mNotification.setDefaults(Notification.DEFAULT_ALL);
// mNotification.setPriority(Notification.PRIORITY_DEFAULT); //通知优先级
// mNotification.flags=Notification.FLAG_ONLY_ALERT_ONCE; //发起通知时震动
mNotification.setContentIntent(pendingIntent);
this.mNotificationBuild = mNotification.build();
if (firstVersionNumber>= 8){
this.NotifiService.notify(this.channelID, this.NotifyID, this.mNotificationBuild);
} else {
this.NotifiService.notify(this.NotifyID, this.mNotificationBuild);
}
if(param.callBack) {
this.main&&this.receiver&&this.main.unregisterReceiver(this.receiver);
this.receiver = this.receiver ? this.receiver : plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {
onReceive: function(context, intent) { //实现onReceiver回调函数
param.callBack(intent.getAction().replace(UNI_MEDIA_BROAD + '.',''));
}
});
var IntentFilter = plus.android.importClass('android.content.IntentFilter');
var filter = new IntentFilter();
filter.addAction(UNI_MEDIA_BROAD + '.prev');
filter.addAction(UNI_MEDIA_BROAD + '.play');
filter.addAction(UNI_MEDIA_BROAD + '.next');
this.main.unregisterReceiver(this.receiver);
this.main.registerReceiver(this.receiver, filter); //注册监听
this.mediaBtn = uni.requireNativePlugin('uniMediaButton'); // 监听线控 需要配合附件中的插件( Android API >= 26)
this.mediaBtn.initMediaButton(res => {
console.log(res.message);
// 绑定失败/销毁
if(res.code == '-1') {
this.mediaBtn = null;
return;
}
// res.keyAction == 1 按键松开 res.keyAction == 0 按键按下 播放按钮肯能只有按下
if(res.keyCode && res.keyAction == '0') {
switch (res.keyCode){
case 88:
param.callBack(
'prev'
);
break;
case 87:
param.callBack(
'next'
);
break;
case 127:
case 126:
param.callBack(
'play'
);
break;
}
}
});
var serv = plus.android.importClass("android.app.Service");
this.serv = this.serv ? this.serv : new serv();
this.serv.startForeground(this.NotifyID, this.mNotificationBuild);
plus.android.autoCollection(serv);
plus.android.autoCollection(IntentFilter);
}
plus.android.autoCollection(Context);
plus.android.autoCollection(BitmapFactory);
plus.android.autoCollection(NotificationManager);
plus.android.autoCollection(Notification);
plus.android.autoCollection(Intent);
plus.android.autoCollection(PendingIntent);
plus.android.autoCollection(androidR);
plus.android.autoCollection(this.receiver);
}catch(e){
console.log(e);
}
}
};
使用方法
// 开启 - 更新标题/播放(暂停)按钮
show();
function show(){
androidNotifi.showNotifi({
title : '通知标题',
subTitle: '通知小标题',
cont : '通知内容',
isPlay: true, // 媒体播放按钮状态(控制播放/暂停按钮样式)
legIcon : '', // 封面图片
Ongoing : false, // 是否可删除
callBack:function(res){
switch (res){
case 'play':
console.log('play');
break;
case 'prev':
console.log('prev');
break;
case 'next':
console.log('next');
break;
}
}
})
}
// 关闭
function hide(){
androidNotifi.hideNotifi();
}
由于Android播放视频没有通知栏控制.开始一直使用XZH-musicNotification 的插件,但是由于版本更新,出现BUG(插件已更新).
但是不能总等插件更新,就自己动动手写了一个Native.js版本,由于手上设备不多,没有测试更多的兼容性.在这里希望大家能勇于使用修改提出问题,完善此通知提示!
附件是线控耳机、蓝牙耳机按键监听插件(API >= 26,X86好像不支持忘了)
代码
const androidNotifi = {
NotifyID: 237,
receiver:null,
NotifiService:null,
serv: null,
intent: null,
mNotificationBuild: null,
mediaBtn: null,
channelID : '1',
channelName : '音乐通知',
notifiImg:{},
getImgTemp: function(audioImage) {
return new Promise(resolve => {
if (this.notifiImg[encodeURIComponent(audioImage)]) {
return resolve(plus.io.convertLocalFileSystemURL(this.notifiImg[encodeURIComponent(audioImage)]));
}
if(!/^http/.test(audioImage)) {
this.notifiImg[encodeURIComponent(audioImage)] = audioImage ? audioImage : '_www/static/image/notifimusic.png';
return resolve(plus.io.convertLocalFileSystemURL(audioImage ? audioImage : '_www/static/image/notifimusic.png'));
}
uni.downloadFile({
url: audioImage,
complete: res => {
this.notifiImg[encodeURIComponent(audioImage)] = res.tempFilePath ? res.tempFilePath : '_www/static/image/notifimusic.png';
return resolve(plus.io.convertLocalFileSystemURL(res.tempFilePath ? res.tempFilePath : '_www/static/image/notifimusic.png'));
}
});
});
},
hideNotifi: function(server = false){
this.main&&this.receiver&&this.main.unregisterReceiver(this.receiver);
server&&this.serv&&this.serv.stopForeground&&this.serv.stopForeground(this.NotifyID, this.mNotificationBuild) ;
if (Number(plus.os.version.split('.')[0])>= 8){
this.NotifiService&&this.NotifiService.cancel&&this.NotifiService.cancel(this.channelID,this.NotifyID);
} else {
this.NotifiService&&this.NotifiService.cancel&&this.NotifiService.cancel(this.NotifyID);
}
this.receiver = null;
this.NotifiService = null;
this.serv = null;
this.intent = null;
this.mNotificationBuild = null;
// this.NotifiService&&this.NotifiService.cancelAll&&this.NotifiService.cancelAll();
this.mediaBtn ? this.mediaBtn.release() : ''; // 线控销毁
},
showNotifi:async function(param) {
if (uni.$_sko.systemInfo.platform != 'android') {
return;
}
try{
param = Object.assign({
title : '通知标题',
subTitle: '',
cont : '通知内容',
isPlay: true, // 媒体播放按钮
legIcon : plus.io.convertLocalFileSystemURL('_www/static/image/notifimusic.png'),
Ongoing : false, // 不可删除
},param);
this.main = this.main ? this.main : plus.android.runtimeMainActivity();
var Context = plus.android.importClass("android.content.Context");
var BitmapFactory = plus.android.importClass("android.graphics.BitmapFactory");
var NotificationManager = plus.android.importClass("android.app.NotificationManager");
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 androidR = plus.android.importClass("android.R");
this.NotifiService = this.NotifiService ? this.NotifiService : this.main.getSystemService(Context.NOTIFICATION_SERVICE);
this.intent = this.intent ? this.intent : new Intent(this.main, this.main.getClass());
var UNI_MEDIA_BROAD = this.main.getPackageName() + '.mediaBtn';
//PendingIntent.getActivity的第二个参数需要设置为随机数,否则多个通知时会导致前面的通知被后面的通知替换Extra的数据
var pendingIntent = PendingIntent.getActivity(this.main, 0, this.intent, PendingIntent.FLAG_CANCEL_CURRENT);
var firstVersionNumber = Number(plus.os.version.split('.')[0]);
var mNotification;
//判断当前系统版本在8.0及以上
if (firstVersionNumber >= 8){
if (this.NotifiService.getNotificationChannel() == null){
var NotificationChannel = plus.android.importClass('android.app.NotificationChannel');
var channel = new NotificationChannel(this.channelID, this.channelName, NotificationManager.IMPORTANCE_HIGH);
this.NotifiService.createNotificationChannel(channel);
plus.android.autoCollection(NotificationChannel);
}
param.callBack&&this.main.startForegroundService(this.intent);
mNotification = new Notification.Builder(this.main, this.channelID);
} else {
mNotification = new Notification.Builder(this.main);
param.callBack&&this.main.startService(this.intent);
}
if(param.callBack) {
mNotification.addAction(androidR.drawable.ic_media_previous, "prev", PendingIntent.getBroadcast(this.main, 0, new Intent().setAction(UNI_MEDIA_BROAD + '.prev'), PendingIntent.FLAG_CANCEL_CURRENT));
mNotification.addAction((param.isPlay ? androidR.drawable.ic_media_pause : androidR.drawable.ic_media_play), "play", PendingIntent.getBroadcast(this.main, 0, new Intent().setAction(UNI_MEDIA_BROAD + '.play'), PendingIntent.FLAG_CANCEL_CURRENT));
mNotification.addAction(androidR.drawable.ic_media_next, "next", PendingIntent.getBroadcast(this.main, 0, new Intent().setAction(UNI_MEDIA_BROAD + '.next'), PendingIntent.FLAG_CANCEL_CURRENT));
var mMediaStyle = new Notification.MediaStyle();
mMediaStyle.setShowActionsInCompactView(0, 1, 2);
mNotification.setStyle(mMediaStyle);
}
mNotification.setOngoing(param.Ongoing);
param.legIcon&&mNotification.setLargeIcon(BitmapFactory.decodeFile(await this.getImgTemp(param.legIcon)));
mNotification.setSmallIcon(param.callBack?androidR.drawable.stat_sys_headset:androidR.drawable.stat_notify_chat); //设置图标
mNotification.setContentTitle(param.title);//设置标题
mNotification.setContentText(param.cont); //设置内容
param.subTitle&&mNotification.setSubText(param.subTitle); //子内容暂时去掉
// mNotification.setAutoCancel(true); //设置点击消失
// mNotification.setShowWhen(true); //显示通知时间
mNotification.setTicker("PadInfo"); //弹出通知
mNotification.setDefaults(Notification.DEFAULT_ALL);
// mNotification.setPriority(Notification.PRIORITY_DEFAULT); //通知优先级
// mNotification.flags=Notification.FLAG_ONLY_ALERT_ONCE; //发起通知时震动
mNotification.setContentIntent(pendingIntent);
this.mNotificationBuild = mNotification.build();
if (firstVersionNumber>= 8){
this.NotifiService.notify(this.channelID, this.NotifyID, this.mNotificationBuild);
} else {
this.NotifiService.notify(this.NotifyID, this.mNotificationBuild);
}
if(param.callBack) {
this.main&&this.receiver&&this.main.unregisterReceiver(this.receiver);
this.receiver = this.receiver ? this.receiver : plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {
onReceive: function(context, intent) { //实现onReceiver回调函数
param.callBack(intent.getAction().replace(UNI_MEDIA_BROAD + '.',''));
}
});
var IntentFilter = plus.android.importClass('android.content.IntentFilter');
var filter = new IntentFilter();
filter.addAction(UNI_MEDIA_BROAD + '.prev');
filter.addAction(UNI_MEDIA_BROAD + '.play');
filter.addAction(UNI_MEDIA_BROAD + '.next');
this.main.unregisterReceiver(this.receiver);
this.main.registerReceiver(this.receiver, filter); //注册监听
this.mediaBtn = uni.requireNativePlugin('uniMediaButton'); // 监听线控 需要配合附件中的插件( Android API >= 26)
this.mediaBtn.initMediaButton(res => {
console.log(res.message);
// 绑定失败/销毁
if(res.code == '-1') {
this.mediaBtn = null;
return;
}
// res.keyAction == 1 按键松开 res.keyAction == 0 按键按下 播放按钮肯能只有按下
if(res.keyCode && res.keyAction == '0') {
switch (res.keyCode){
case 88:
param.callBack(
'prev'
);
break;
case 87:
param.callBack(
'next'
);
break;
case 127:
case 126:
param.callBack(
'play'
);
break;
}
}
});
var serv = plus.android.importClass("android.app.Service");
this.serv = this.serv ? this.serv : new serv();
this.serv.startForeground(this.NotifyID, this.mNotificationBuild);
plus.android.autoCollection(serv);
plus.android.autoCollection(IntentFilter);
}
plus.android.autoCollection(Context);
plus.android.autoCollection(BitmapFactory);
plus.android.autoCollection(NotificationManager);
plus.android.autoCollection(Notification);
plus.android.autoCollection(Intent);
plus.android.autoCollection(PendingIntent);
plus.android.autoCollection(androidR);
plus.android.autoCollection(this.receiver);
}catch(e){
console.log(e);
}
}
};
使用方法
// 开启 - 更新标题/播放(暂停)按钮
show();
function show(){
androidNotifi.showNotifi({
title : '通知标题',
subTitle: '通知小标题',
cont : '通知内容',
isPlay: true, // 媒体播放按钮状态(控制播放/暂停按钮样式)
legIcon : '', // 封面图片
Ongoing : false, // 是否可删除
callBack:function(res){
switch (res){
case 'play':
console.log('play');
break;
case 'prev':
console.log('prev');
break;
case 'next':
console.log('next');
break;
}
}
})
}
// 关闭
function hide(){
androidNotifi.hideNotifi();
}
由于Android播放视频没有通知栏控制.开始一直使用XZH-musicNotification 的插件,但是由于版本更新,出现BUG(插件已更新).
但是不能总等插件更新,就自己动动手写了一个Native.js版本,由于手上设备不多,没有测试更多的兼容性.在这里希望大家能勇于使用修改提出问题,完善此通知提示!
附件是线控耳机、蓝牙耳机按键监听插件(API >= 26,X86好像不支持忘了)

银联云闪付小程序开发
分享一下我们开发的云闪付小程序PHP后端开发包,unionpay 云闪付小程序开发包
银联云闪付小程序非官方开发包,这可能是第一个支持composer导入的云闪付小程序开发包,小程序后端相关接口与支付相关接口已全部更新完毕。
码云地址:https://gitee.com/leapy/unionpay
Github地址:https://github.com/ileapy/unionpay
vue前端开发包(不建议这样引用)
> npm install upsdk-vue
有需要公众号和小程序开发的可以联系我,我们有团队:
邮箱:cfn@leapy.cn
微信:SH-CFN
分享一下我们开发的云闪付小程序PHP后端开发包,unionpay 云闪付小程序开发包
银联云闪付小程序非官方开发包,这可能是第一个支持composer导入的云闪付小程序开发包,小程序后端相关接口与支付相关接口已全部更新完毕。
码云地址:https://gitee.com/leapy/unionpay
Github地址:https://github.com/ileapy/unionpay
vue前端开发包(不建议这样引用)
> npm install upsdk-vue
有需要公众号和小程序开发的可以联系我,我们有团队:
邮箱:cfn@leapy.cn
微信:SH-CFN