HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

cover-view里的文本不能换行-vue

Vue uniapp HBuilder

cover-view里的文本不能换行可能是样式问题,在这个范围内再去找问题,一般 white-space: normal;可以解决问题,防止万一加一个!important,在cover-view就可以,但是存在换行成功,却没有文字显示,同时高度有变化却没有设置高度,这时再加上 line-height:normal!important;,让其显示出来,
原因如下:
cover-view默认属性有(好像是小程序的):
cover-view {
display:block;
line-height:1.2;
overflow:hidden;
white-space:nowrap;
pointer-events:auto;
}

注意:可以换行后,每个cover-view建议加一个高度或是单行white-space属性不为normal,如果单行没有高度或是单行white-space属性为normal,在安卓中可能不显示。

参考:https://www.jianshu.com/p/3c255f5c94f9?from=singlemessage

继续阅读 »

cover-view里的文本不能换行可能是样式问题,在这个范围内再去找问题,一般 white-space: normal;可以解决问题,防止万一加一个!important,在cover-view就可以,但是存在换行成功,却没有文字显示,同时高度有变化却没有设置高度,这时再加上 line-height:normal!important;,让其显示出来,
原因如下:
cover-view默认属性有(好像是小程序的):
cover-view {
display:block;
line-height:1.2;
overflow:hidden;
white-space:nowrap;
pointer-events:auto;
}

注意:可以换行后,每个cover-view建议加一个高度或是单行white-space属性不为normal,如果单行没有高度或是单行white-space属性为normal,在安卓中可能不显示。

参考:https://www.jianshu.com/p/3c255f5c94f9?from=singlemessage

收起阅读 »

uni-app打包h5 报内存不够

FATAL ERROR: Scavenger: semi-space copy
[HBuilder] 09:58:42.799 Allocation failed - process out of memory
[HBuilder] 09:58:42.814 1: 00B4238E

参考方案

继续阅读 »

FATAL ERROR: Scavenger: semi-space copy
[HBuilder] 09:58:42.799 Allocation failed - process out of memory
[HBuilder] 09:58:42.814 1: 00B4238E

参考方案

收起阅读 »

mui 只许上拉加载

mui

工作中用mui时出现一个问题,需求是只要上拉加载,但出现了下拉也加载的情况,现在有一个解决办法,如下:
添加 down : {
style:'circle',//必选,下拉刷新样式,目前支持原生5+ ‘circle’ 样式
color:'#2BD009', //可选,默认“#2BD009” 下拉刷新控件颜色
height:'50px',//可选,默认50px.下拉刷新控件的高度,
range:'100px', //可选 默认100px,控件可下拉拖拽的范围
offset:'0px', //可选 默认0px,下拉刷新控件的起始位置
auto: false,//可选,默认false.首次加载自动上拉刷新一次
callback :()=>{
this.disablePulldownToRefresh()
} //必选,刷新函数,根据具体业务来编写,比如通过ajax从服务器获取新数据;
}

继续阅读 »

工作中用mui时出现一个问题,需求是只要上拉加载,但出现了下拉也加载的情况,现在有一个解决办法,如下:
添加 down : {
style:'circle',//必选,下拉刷新样式,目前支持原生5+ ‘circle’ 样式
color:'#2BD009', //可选,默认“#2BD009” 下拉刷新控件颜色
height:'50px',//可选,默认50px.下拉刷新控件的高度,
range:'100px', //可选 默认100px,控件可下拉拖拽的范围
offset:'0px', //可选 默认0px,下拉刷新控件的起始位置
auto: false,//可选,默认false.首次加载自动上拉刷新一次
callback :()=>{
this.disablePulldownToRefresh()
} //必选,刷新函数,根据具体业务来编写,比如通过ajax从服务器获取新数据;
}

收起阅读 »

5+APP安卓原生插件开发全流程个人总结

5 插件 插件开发 5+App开发 5+sdk

1、离线打包

Hbuilder官方路径:https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android

为什么要用离线打包呢,因为是开发安卓第三方插件,主要用的是Android Stuido,所以把5+APP项目导到Android studio里来,方便开发和测试。

其实还有一个原因,涉及到的第三方插件用到了系统级权限,要用platform.pk8来签名打包,才能运行。所以用离线打包会方便点。

Hbuilder(X)用不了pk8签名,当然,你可以把pk8转换成keystore文件,这样就可以签名了。

这里有大佬介绍转换,不过我还没试。(https://blog.csdn.net/langlitaojin/article/details/108045709)

2、添加第三方插件文件及支持
将第三方插件的jar包,so文件拷贝到Android studio相应的目录(app-libs)下,然后在gradle最外层配置:
repositories {
flatDir {
dirs 'libs'
}
}
在dependencies层加入:

implementation fileTree(dir: 'libs', include: ['.aar', '.jar', '*.so'], exclude: [])
注意:有so文件的话,需要在gradle的android层配置ndk支持。

ndk {
// 设置支持的SO库架构
abiFilters 'armeabi' ,'x86', 'armeabi-v7a'
}

3、创建java类封装第三方插件所要用到的功能,封装成一个个独立的方法。数据传递到js端:广播,或者用接口类回调。

这个有个地方要注意,如果注册了广播监听者,没有注销的话,应用退出再重新打开之后,会报:

IllegalArgumentException: Receiver not registered。

我用5+的方法去注销在java里注册的广播,但是没起到效果,不得其解。

然后我转而在java层封装了一个注销监听器的方法,然后在js层调用,问题就没再出现了。

所以呢,我觉得原生的方法就尽量在java层里写好,由js层调用,避免用5+来写。

这里呢,我觉得还是少用广播吧,注销是个麻烦事,在java里可以在专门的生命周期里注销,但是在js里,就麻烦了,要在各种事件(页面上的返回键或关闭键,手机上的虚拟或物理返回)上去监听做注销处理。

4、创建一个js类,用5+API来封装上面封装好的java类的方法。

用java封装完第三方库,接着就是在js也封装一个相应的api,方便前端开发人员使用,也方便维护。


注意:如果是系统级应用,那么要hook一下webview(因为webview存在安全漏洞,从安卓5.1开始,谷歌禁止系统应用使用webview)。

提示:Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes

解决方法:

1、首先呢,创建一个Application继承自DCloudApplication,然后在AndroidManifest.xml里,引用自己的Application,且加上tools:replace="android:name",避免与Hbuilder的lib里的DCloudApplication冲突

2、在application的onCreate方法的super方法前,调用hook webview的方法,来绕过谷歌的禁用。

具体hook的方法:https://www.52pojie.cn/thread-992014-1-1.html

继续阅读 »

1、离线打包

Hbuilder官方路径:https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android

为什么要用离线打包呢,因为是开发安卓第三方插件,主要用的是Android Stuido,所以把5+APP项目导到Android studio里来,方便开发和测试。

其实还有一个原因,涉及到的第三方插件用到了系统级权限,要用platform.pk8来签名打包,才能运行。所以用离线打包会方便点。

Hbuilder(X)用不了pk8签名,当然,你可以把pk8转换成keystore文件,这样就可以签名了。

这里有大佬介绍转换,不过我还没试。(https://blog.csdn.net/langlitaojin/article/details/108045709)

2、添加第三方插件文件及支持
将第三方插件的jar包,so文件拷贝到Android studio相应的目录(app-libs)下,然后在gradle最外层配置:
repositories {
flatDir {
dirs 'libs'
}
}
在dependencies层加入:

implementation fileTree(dir: 'libs', include: ['.aar', '.jar', '*.so'], exclude: [])
注意:有so文件的话,需要在gradle的android层配置ndk支持。

ndk {
// 设置支持的SO库架构
abiFilters 'armeabi' ,'x86', 'armeabi-v7a'
}

3、创建java类封装第三方插件所要用到的功能,封装成一个个独立的方法。数据传递到js端:广播,或者用接口类回调。

这个有个地方要注意,如果注册了广播监听者,没有注销的话,应用退出再重新打开之后,会报:

IllegalArgumentException: Receiver not registered。

我用5+的方法去注销在java里注册的广播,但是没起到效果,不得其解。

然后我转而在java层封装了一个注销监听器的方法,然后在js层调用,问题就没再出现了。

所以呢,我觉得原生的方法就尽量在java层里写好,由js层调用,避免用5+来写。

这里呢,我觉得还是少用广播吧,注销是个麻烦事,在java里可以在专门的生命周期里注销,但是在js里,就麻烦了,要在各种事件(页面上的返回键或关闭键,手机上的虚拟或物理返回)上去监听做注销处理。

4、创建一个js类,用5+API来封装上面封装好的java类的方法。

用java封装完第三方库,接着就是在js也封装一个相应的api,方便前端开发人员使用,也方便维护。


注意:如果是系统级应用,那么要hook一下webview(因为webview存在安全漏洞,从安卓5.1开始,谷歌禁止系统应用使用webview)。

提示:Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes

解决方法:

1、首先呢,创建一个Application继承自DCloudApplication,然后在AndroidManifest.xml里,引用自己的Application,且加上tools:replace="android:name",避免与Hbuilder的lib里的DCloudApplication冲突

2、在application的onCreate方法的super方法前,调用hook webview的方法,来绕过谷歌的禁用。

具体hook的方法:https://www.52pojie.cn/thread-992014-1-1.html

收起阅读 »

canvas组件在android手机使用CanvasContext.draw可能绘制不完整的解决办法

Android canvas

在android手机的app中使用canvas组件的CanvasContext.draw方法,可能导致绘制不完整,估计原因是手机计算draw之前的一系列代码没有完成,解决办法是使用以下代码延时执行CanvasContext.draw方法。实测成功。

// #ifdef APP-PLUS  
if(plus.os.name == "Android"){  
    setTimeout(()=>{  
        this.context.draw(true, ()=>{  
            console.log('createBill success');  
            callback()  
        })  
    }, 100)  
}else{  
    this.context.draw(true, ()=>{  
        console.log('createBill success');  
        callback()  
    })  
}  
// #endif  
// #ifndef APP-PLUS  
this.context.draw(true, ()=>{  
    console.log('createBill success');  
    callback()  
})  
// #endif
继续阅读 »

在android手机的app中使用canvas组件的CanvasContext.draw方法,可能导致绘制不完整,估计原因是手机计算draw之前的一系列代码没有完成,解决办法是使用以下代码延时执行CanvasContext.draw方法。实测成功。

// #ifdef APP-PLUS  
if(plus.os.name == "Android"){  
    setTimeout(()=>{  
        this.context.draw(true, ()=>{  
            console.log('createBill success');  
            callback()  
        })  
    }, 100)  
}else{  
    this.context.draw(true, ()=>{  
        console.log('createBill success');  
        callback()  
    })  
}  
// #endif  
// #ifndef APP-PLUS  
this.context.draw(true, ()=>{  
    console.log('createBill success');  
    callback()  
})  
// #endif
收起阅读 »

关于Mac版Hbuilder X文件查找失败的bug的【解决方案】

问题描述

Mac版Hbuilder X创建uni-app项目后,运行时会提示“文件查找失败,找不到xxxx/main.js”。

解决方案:

1.将新创建的项目【从项目列表移除】
2.选择【文件-打开目录】重新打开之前创建的项目

此时就可以运行成功。

另外如果提示“尚不支持此种类型文件”,在排除真的是类型原因的情况下,按以上方式操作也能解决该问题。

具体是不是bug,目前还不清楚,这个问题困扰了好久,网上也找不到答案,所以写出来,分享给有同样问题的小伙伴。

继续阅读 »

问题描述

Mac版Hbuilder X创建uni-app项目后,运行时会提示“文件查找失败,找不到xxxx/main.js”。

解决方案:

1.将新创建的项目【从项目列表移除】
2.选择【文件-打开目录】重新打开之前创建的项目

此时就可以运行成功。

另外如果提示“尚不支持此种类型文件”,在排除真的是类型原因的情况下,按以上方式操作也能解决该问题。

具体是不是bug,目前还不清楚,这个问题困扰了好久,网上也找不到答案,所以写出来,分享给有同样问题的小伙伴。

收起阅读 »

iOS马甲包上架方法论

iOS 外包 招聘

> 马甲包是利用各大市场规则漏洞,通过技术手段,多次上架同一款产品的方法。马甲包和主产品包拥有同样的内容和功能,除了icon和应用名称不能完全一致,其他基本一致。
至于为什么做马甲包,能读这篇文章的自然也不需要我多说什么了吧,引流、抗风险、关键词覆盖、刷榜,对于一些灰色产业或者用户获取竞争激烈的行业领域来说,意义非凡。但是苹果爸爸可不允许这种情况发生,马甲包在审核环节,是非常容易被拒的,毕竟破坏苹果商店公平性的东西,是不被允许的。

当然,我们对iOS的审核机制进行了深入的研究和尝试,马甲包也是成功上架过很多了。马甲包该如何上架呢?找我就好啦~ 哈哈哈!!言归正传,下文详述。

那么马甲包该如何上架?

需要马甲包代上架的可以联系我,QQ:1481983952

马甲包被拒最常见的4.3被拒

  1. 3 Design: SpamGuideline 4.3 - Design

首先4.3基本是机器审,是你之前用这套源码上过一个包,现在用这套代码直接改一个logo跟名字再上一个马甲,这种基本会直接4.3

这种情况基本要改源码,First:文件夹的名字全部进行修改。Second:工程都有一个class前缀, 我们要取一个长一点的class前缀, 并且这个类前缀在你的整个工程一定是一个唯一的字符串, 我们假设这个类前缀是iosMaJiaBao, 现在我们需要生成一个控制器, 控制器的结尾Controller也需要用一个特定的字符去代替, 比如:Director,剩下的View以及object做法类似, 就不一一介绍了,做马甲的时候就是把这些名字用另一个唯一的字符去代替, 尽量长一点。Third:把另一个其他的工程中的类全部导入进来, 作用是混淆代码, 在现有的工程中调用, 可以没有任何效果, 只是单纯相互调用而已~~~

别想着单一加垃圾代码,没用的!!!

其实还有很多别的情况,下次再一一解释并给出解决方案吧,今天有点懒了呢~

继续阅读 »

> 马甲包是利用各大市场规则漏洞,通过技术手段,多次上架同一款产品的方法。马甲包和主产品包拥有同样的内容和功能,除了icon和应用名称不能完全一致,其他基本一致。
至于为什么做马甲包,能读这篇文章的自然也不需要我多说什么了吧,引流、抗风险、关键词覆盖、刷榜,对于一些灰色产业或者用户获取竞争激烈的行业领域来说,意义非凡。但是苹果爸爸可不允许这种情况发生,马甲包在审核环节,是非常容易被拒的,毕竟破坏苹果商店公平性的东西,是不被允许的。

当然,我们对iOS的审核机制进行了深入的研究和尝试,马甲包也是成功上架过很多了。马甲包该如何上架呢?找我就好啦~ 哈哈哈!!言归正传,下文详述。

那么马甲包该如何上架?

需要马甲包代上架的可以联系我,QQ:1481983952

马甲包被拒最常见的4.3被拒

  1. 3 Design: SpamGuideline 4.3 - Design

首先4.3基本是机器审,是你之前用这套源码上过一个包,现在用这套代码直接改一个logo跟名字再上一个马甲,这种基本会直接4.3

这种情况基本要改源码,First:文件夹的名字全部进行修改。Second:工程都有一个class前缀, 我们要取一个长一点的class前缀, 并且这个类前缀在你的整个工程一定是一个唯一的字符串, 我们假设这个类前缀是iosMaJiaBao, 现在我们需要生成一个控制器, 控制器的结尾Controller也需要用一个特定的字符去代替, 比如:Director,剩下的View以及object做法类似, 就不一一介绍了,做马甲的时候就是把这些名字用另一个唯一的字符去代替, 尽量长一点。Third:把另一个其他的工程中的类全部导入进来, 作用是混淆代码, 在现有的工程中调用, 可以没有任何效果, 只是单纯相互调用而已~~~

别想着单一加垃圾代码,没用的!!!

其实还有很多别的情况,下次再一一解释并给出解决方案吧,今天有点懒了呢~

收起阅读 »

uniapp向webview中发送消息

uniapp

uniapp向webview中发送消息

在业务开发中,使用webview嵌套了vue开发的h5页面,进行套壳打包,其一需求是,在h5中获取当前app的版本号,就涉及到了uniapp向webview传递消息的场景

uniapp 中代码

核心为获取到webview窗口,然后通过evalJS执行h5中的方法

  • setVersion方法为h5页面中定义的全局方法
<template>  
    <view class="content">  
        <!-- 开发 -->  
        <web-view @message="onMessage" :webview-styles="webviewStyles" src="http://192.168.1.158:3000"></web-view>  

    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            title: 'Hello',  
            webviewStyles: {  
                progress: {  
                    color: '#f0b90b'  
                }  
            },  
            wv: null,  
        };  
    },  
    onLoad() {  
        const self = this;  
        // #ifdef APP-PLUS  
        let currentWebview = this.$scope.$getAppWebview();  
        setTimeout(function() {  
            let wv = currentWebview.children()[0];  
            self.wv = wv;  
            self.setVersion();  
        }, 1000);  
        // #endif  

    },  
    methods: {  
        // 设置版本号  
        setVersion() {  
            const self = this;  
            plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  
                self.wv.evalJS("setVersion('" + widgetInfo.version + "')");  
            });  
        },  
        // 接收消息  
        onMessage(e) {  
            const self = this;  
            console.log('我收到了网页发来的消息', e.detail.data);  
            let data = e.detail.data;  
        },  
    }  
};  
</script>  

h5 中代码

App.vue

// 设置版本号  
    window.setVersion = (id) => {  
      localStorage.setItem("version", version);  
    };

然后就可以在h5中获取使用了

注意

尽量不要uni生命周期中直接调用h5里面的方法,要等h5加载完成后,才可以调用

继续阅读 »

uniapp向webview中发送消息

在业务开发中,使用webview嵌套了vue开发的h5页面,进行套壳打包,其一需求是,在h5中获取当前app的版本号,就涉及到了uniapp向webview传递消息的场景

uniapp 中代码

核心为获取到webview窗口,然后通过evalJS执行h5中的方法

  • setVersion方法为h5页面中定义的全局方法
<template>  
    <view class="content">  
        <!-- 开发 -->  
        <web-view @message="onMessage" :webview-styles="webviewStyles" src="http://192.168.1.158:3000"></web-view>  

    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            title: 'Hello',  
            webviewStyles: {  
                progress: {  
                    color: '#f0b90b'  
                }  
            },  
            wv: null,  
        };  
    },  
    onLoad() {  
        const self = this;  
        // #ifdef APP-PLUS  
        let currentWebview = this.$scope.$getAppWebview();  
        setTimeout(function() {  
            let wv = currentWebview.children()[0];  
            self.wv = wv;  
            self.setVersion();  
        }, 1000);  
        // #endif  

    },  
    methods: {  
        // 设置版本号  
        setVersion() {  
            const self = this;  
            plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  
                self.wv.evalJS("setVersion('" + widgetInfo.version + "')");  
            });  
        },  
        // 接收消息  
        onMessage(e) {  
            const self = this;  
            console.log('我收到了网页发来的消息', e.detail.data);  
            let data = e.detail.data;  
        },  
    }  
};  
</script>  

h5 中代码

App.vue

// 设置版本号  
    window.setVersion = (id) => {  
      localStorage.setItem("version", version);  
    };

然后就可以在h5中获取使用了

注意

尽量不要uni生命周期中直接调用h5里面的方法,要等h5加载完成后,才可以调用

收起阅读 »

uniapp原生插件-监听手机短信

原生插件

监听手机短信

实时监控手机收到的短信,可获取到发送者的手机号、时间、内容、卡槽等相关信息

使用方法

  • 下载本插件并存放到nativeplugins目录下

  • 在页面中引入这个插件

    // 监听短信插件  
    const kingReceiceSmsModule = uni.requireNativePlugin("king-receive-sms")  
  • 调用插件的方法

    kingReceiceSmsModule.addCustomizeNotifyMessage(result => {  
        <!-- result 为监听到的信息 -->  
        var str = JSON.stringify(result);  
        console.log(str)  
    });  

    信息格式

    {  
    "timestamp":1611751876000,  
    "originatingAddress":"+86666666",  
    "body":"我是信息内容",  
    "subId":0  
    }
  • timestamp 接收的时间

  • originatingAddress 发送者的号码

  • body 信息内容

  • subId 卡槽下标

注意事项

  • 使用前,请确认已经开通 短信读取权限接收新短信权限
  • 如果没有开通,请引导用户进行授权,可建议使用这个插件 App权限判断和提示,进行判断开启

java 核心源代码

package io.king.uniplugin;  

import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.os.Build;  
import android.os.Bundle;  
import android.provider.Telephony;  
import android.telephony.SmsMessage;  
import android.util.Log;  

import java.lang.reflect.Method;  
import java.util.HashMap;  
import java.util.Map;  

public class SmsReceiver extends BroadcastReceiver {  

    public static final String TAG = "SmsListenerPackage";  
    public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";  

    private void receiveMessages(SmsMessage[] messages) throws Exception {  
        if (messages == null) {  
            return;  
        }  

        Class ownerClass = Class.forName("android.telephony.SmsMessage");  
        Method method = ownerClass.getMethod("getSubId");  

        Map<String, String> msg = new HashMap<String, String>(messages.length);  
        Map<String, Integer> msgSubId = new HashMap<String, Integer>(messages.length);  
        Map<String, Long> msgTime = new HashMap<String, Long>(messages.length);  
        for (SmsMessage message : messages) {  
            String originatingAddress = message.getOriginatingAddress();  

            // Check if index with number exists  
            if (!msg.containsKey(originatingAddress)) {  
                msg.put(originatingAddress, message.getMessageBody());  
                int subId = (int) method.invoke(message);  
                msgSubId.put(originatingAddress, subId);  
                msgTime.put(originatingAddress, message.getTimestampMillis());  
            } else {  
                String previousParts = msg.get(originatingAddress);  
                String msgString = previousParts + message.getMessageBody();  
                msg.put(originatingAddress, msgString);  
            }  
        }  

        for (String sender : msg.keySet()) {  
            Log.d(  
                    TAG,  
                    String.format("%s: %s", sender, msg.get(sender))  
            );  

            Map<String, Object> receivedMessage = new HashMap<>();  

            receivedMessage.put("originatingAddress", sender);  
            receivedMessage.put("body", msg.get(sender));  
            receivedMessage.put("timestamp", msgTime.get(sender));  
            receivedMessage.put("subId", msgSubId.get(sender));  

            if (CallBack.getInstance().customizeNotifyMessage != null) {  
                CallBack.getInstance().customizeNotifyMessage.onCustomizeNotifyMessage(receivedMessage);  
            }  
        }  
    }  

    @Override  
    public void onReceive(Context context, Intent intent) {  
        SmsMessage[] messages = null;  

        if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {  
            try {  
                final Bundle bundle = intent.getExtras();  

                if (bundle == null || !bundle.containsKey("pdus")) {  
                    return;  
                }  

                final Object[] pdus = (Object[]) bundle.get("pdus");  
                messages = new SmsMessage[pdus.length];  

                for (int i = 0; i < pdus.length; i++) {  
                    byte[] pdu = (byte[]) pdus[i];  
                    messages[i] = SmsMessage.createFromPdu(pdu);  
                    Log.e(TAG,  messages[i].getMessageBody());  
                }  

            } catch (Exception e) {  
                Log.e(TAG, e.getMessage());  
            }  
        }  

        try {  
            receiveMessages(messages);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}
继续阅读 »

监听手机短信

实时监控手机收到的短信,可获取到发送者的手机号、时间、内容、卡槽等相关信息

使用方法

  • 下载本插件并存放到nativeplugins目录下

  • 在页面中引入这个插件

    // 监听短信插件  
    const kingReceiceSmsModule = uni.requireNativePlugin("king-receive-sms")  
  • 调用插件的方法

    kingReceiceSmsModule.addCustomizeNotifyMessage(result => {  
        <!-- result 为监听到的信息 -->  
        var str = JSON.stringify(result);  
        console.log(str)  
    });  

    信息格式

    {  
    "timestamp":1611751876000,  
    "originatingAddress":"+86666666",  
    "body":"我是信息内容",  
    "subId":0  
    }
  • timestamp 接收的时间

  • originatingAddress 发送者的号码

  • body 信息内容

  • subId 卡槽下标

注意事项

  • 使用前,请确认已经开通 短信读取权限接收新短信权限
  • 如果没有开通,请引导用户进行授权,可建议使用这个插件 App权限判断和提示,进行判断开启

java 核心源代码

package io.king.uniplugin;  

import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.os.Build;  
import android.os.Bundle;  
import android.provider.Telephony;  
import android.telephony.SmsMessage;  
import android.util.Log;  

import java.lang.reflect.Method;  
import java.util.HashMap;  
import java.util.Map;  

public class SmsReceiver extends BroadcastReceiver {  

    public static final String TAG = "SmsListenerPackage";  
    public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";  

    private void receiveMessages(SmsMessage[] messages) throws Exception {  
        if (messages == null) {  
            return;  
        }  

        Class ownerClass = Class.forName("android.telephony.SmsMessage");  
        Method method = ownerClass.getMethod("getSubId");  

        Map<String, String> msg = new HashMap<String, String>(messages.length);  
        Map<String, Integer> msgSubId = new HashMap<String, Integer>(messages.length);  
        Map<String, Long> msgTime = new HashMap<String, Long>(messages.length);  
        for (SmsMessage message : messages) {  
            String originatingAddress = message.getOriginatingAddress();  

            // Check if index with number exists  
            if (!msg.containsKey(originatingAddress)) {  
                msg.put(originatingAddress, message.getMessageBody());  
                int subId = (int) method.invoke(message);  
                msgSubId.put(originatingAddress, subId);  
                msgTime.put(originatingAddress, message.getTimestampMillis());  
            } else {  
                String previousParts = msg.get(originatingAddress);  
                String msgString = previousParts + message.getMessageBody();  
                msg.put(originatingAddress, msgString);  
            }  
        }  

        for (String sender : msg.keySet()) {  
            Log.d(  
                    TAG,  
                    String.format("%s: %s", sender, msg.get(sender))  
            );  

            Map<String, Object> receivedMessage = new HashMap<>();  

            receivedMessage.put("originatingAddress", sender);  
            receivedMessage.put("body", msg.get(sender));  
            receivedMessage.put("timestamp", msgTime.get(sender));  
            receivedMessage.put("subId", msgSubId.get(sender));  

            if (CallBack.getInstance().customizeNotifyMessage != null) {  
                CallBack.getInstance().customizeNotifyMessage.onCustomizeNotifyMessage(receivedMessage);  
            }  
        }  
    }  

    @Override  
    public void onReceive(Context context, Intent intent) {  
        SmsMessage[] messages = null;  

        if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {  
            try {  
                final Bundle bundle = intent.getExtras();  

                if (bundle == null || !bundle.containsKey("pdus")) {  
                    return;  
                }  

                final Object[] pdus = (Object[]) bundle.get("pdus");  
                messages = new SmsMessage[pdus.length];  

                for (int i = 0; i < pdus.length; i++) {  
                    byte[] pdu = (byte[]) pdus[i];  
                    messages[i] = SmsMessage.createFromPdu(pdu);  
                    Log.e(TAG,  messages[i].getMessageBody());  
                }  

            } catch (Exception e) {  
                Log.e(TAG, e.getMessage());  
            }  
        }  

        try {  
            receiveMessages(messages);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}
收起阅读 »

提供兼职实习岗位(前端)

此贴发布于2021年1月27日
有效期10天
到2021年2月7号后失效

本人运营了一个电商类型的网站.目前有4个项目

  • 移动端 uni-app + ts
  • pc端 vue3.x + ts
  • 管理后台1 uni-cloud-admin + ts + uni-clound-db
  • 管理后台2 react + ts + 原生uni-cloud

目前全部是自己开发.由于还在上班.精力不够.找1到2个学生或者初级前端一起开发

每个月1000到1500的补贴
更重要的是
带着你一起熟悉正规互联网公司的开发流程

要求
有一定的前端开发基础
好学
吃苦

需要回答以下几个问题
js和vue的区别
uni-app和vue的区别
uni-cloud和restfull的区别
你的前端职业规划
如果你没用过ts,你计划怎么学习

有意者加微信ranwawag

继续阅读 »

此贴发布于2021年1月27日
有效期10天
到2021年2月7号后失效

本人运营了一个电商类型的网站.目前有4个项目

  • 移动端 uni-app + ts
  • pc端 vue3.x + ts
  • 管理后台1 uni-cloud-admin + ts + uni-clound-db
  • 管理后台2 react + ts + 原生uni-cloud

目前全部是自己开发.由于还在上班.精力不够.找1到2个学生或者初级前端一起开发

每个月1000到1500的补贴
更重要的是
带着你一起熟悉正规互联网公司的开发流程

要求
有一定的前端开发基础
好学
吃苦

需要回答以下几个问题
js和vue的区别
uni-app和vue的区别
uni-cloud和restfull的区别
你的前端职业规划
如果你没用过ts,你计划怎么学习

有意者加微信ranwawag

收起阅读 »