HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

Loading图总有一款适合你的

loading uniapp

总有一款适合你的Loading

github地址,喜欢的可以star下哦

插件预览图

使用教程

1.插件代码拷贝

  • 下载后把components目录下countUp.vue文件拷贝到自己项目目录下

2.插件全局配置

  • 在项目里main.js中配置如下代码
import loading from './components/loading/loading.vue'  

Vue.component('loading',loading)  

3.插件使用

  • vue页面使用
<template>  
    <view>  
        <loading ></loading>  
    </view>  
</template>  

<script>  
</script>  

<style>  
</style>  

还收集了一些其他的Loding

Loaders.css

css-loaders

SVG-Loaders

暂时收集了这些,我相信能满足大部分人的需求了

兼容性

uni-app项目中使用都兼容

继续阅读 »

总有一款适合你的Loading

github地址,喜欢的可以star下哦

插件预览图

使用教程

1.插件代码拷贝

  • 下载后把components目录下countUp.vue文件拷贝到自己项目目录下

2.插件全局配置

  • 在项目里main.js中配置如下代码
import loading from './components/loading/loading.vue'  

Vue.component('loading',loading)  

3.插件使用

  • vue页面使用
<template>  
    <view>  
        <loading ></loading>  
    </view>  
</template>  

<script>  
</script>  

<style>  
</style>  

还收集了一些其他的Loding

Loaders.css

css-loaders

SVG-Loaders

暂时收集了这些,我相信能满足大部分人的需求了

兼容性

uni-app项目中使用都兼容

收起阅读 »

uni.navigateTo 的url不能用变量拼接的方式吗 求大神解答

navigateto

uni.navigateTo({
url:"/pages/member/"+k+"/"+k
})
如上写法 页面会报错navigateTo:fail page /pages/member/set_phone/set_phone is not found,可是我页面是真实存在的。
如果真不能这样写的话 那应该怎么写 难道一个一个判断 然后写???

继续阅读 »

uni.navigateTo({
url:"/pages/member/"+k+"/"+k
})
如上写法 页面会报错navigateTo:fail page /pages/member/set_phone/set_phone is not found,可是我页面是真实存在的。
如果真不能这样写的话 那应该怎么写 难道一个一个判断 然后写???

收起阅读 »

uniapp NFC可读写nfcv格式的nfc标签

NFC uniapp

需求:

在实现了可读写nfc(ndef)标签后,需要兼容另一个标签格式nfcv。

uniapp下nfc如果没有读到参考 uniapp 实现 NFC标签读取 和 写入

读:

java参考代码

private void readNfcv(Tag tag) {  
        System.out.println("进入readNfcv方法");  
        NfcV tech = NfcV.get(tag);  
        if (tech != null) {  
            try {  
                tech.connect();  
                if (tech.isConnected()) {  
                    byte[] tagUid = tag.getId();  
                    System.out.println("ceshi00000:"+tagUid);  
                    // store tag UID for use in addressed commands  
                    //读第一个block  
                    byte[] read = new byte[]{  
                            (byte) 0x22,  // FLAGS  
                            (byte) 0x23,  // 20-READ_SINGLE_BLOCK,23-所有块  
                            0, 0, 0, 0, 0, 0, 0, 0,  
                            0, 0  
                    };  
                    System.out.println("ceshi:"+read);  
                    System.arraycopy(tagUid, 0, read, 2, tagUid.length);  // paste tag UID into command  
                    byte[] res = tech.transceive(read);  
                    System.out.println("2222222:"+res);  
                    if (res != null) {  
                        System.out.println("标记:"+ Arrays.toString(res));  
                        //nfcContent.append("NfcV: " + new String(res, Charset.forName("utf-8")));  
                        if(res[1] == 'H'&& res[2] =='J' && res[3] == 'I'){  
                            int blockAddress = 1;  
                            int blocknum = res[4];  
                            byte[] cmd = new byte[]{  
                                    (byte) 0x22,  // FLAGS  
                                    (byte) 0x23,  // 20-READ_SINGLE_BLOCK,23-所有块  
                                    0, 0, 0, 0, 0, 0, 0, 0,  
                                    (byte) (blockAddress & 0x0ff), (byte) (blocknum - 1 & 0x0ff)  
                            };  
                            System.arraycopy(tagUid, 0, cmd, 2, tagUid.length);  // paste tag UID into command  
                            byte[] response = tech.transceive(cmd);  
                            System.out.println("主要数据"+Arrays.toString(response));  
                            if (response != null) {  
                                nfcContent.append("NfcV: " + new String(response, Charset.forName("utf-8")));  
                            }  
                        }  
                    }  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }finally {  
                try {  
                    tech.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }

js实现代码:

        readNfcV(intent) {  
            var NfcV = plus.android.importClass('android.nfc.tech.NfcV');  
            var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
            // console.log(tag);  
            console.log(NfcV.get(tag));  
            var tech = NfcV.get(tag);  
            if (tech != null) {  
                try {  
                    tech.connect();  
                    console.log(tech.isConnected());  
                    if (tech.isConnected()) {  
                        console.log('卡片字节数组ID:' + tag.getId());  
                        var tagUid = tag.getId();  
                        var buffer = [];  
                        buffer[0] = 0x22;  
                        buffer[1] = 0x23;  
                        for (var i in tagUid) {  
                            // console.log(tagUid[i]);  
                            buffer.push(tagUid[i]);  
                        }  
                        buffer[10] = 0;  
                        buffer[11] = 0;  
                        console.log(buffer);  
                        var res = tech.transceive(buffer);  
                        if (res != null) {  
                            console.log('标记:' + res);  
                            if (String.fromCharCode(res[1]) == 'H' && String.fromCharCode(res[2]) == 'J' && String.fromCharCode(res[3]) == 'I') {  
                                var blockAddress = 1;  
                                var blocknum = res[4];  
                                var cmd = [];  
                                cmd[0] = 0x22;  
                                cmd[1] = 0x23;  
                                for (var i in tagUid) {  
                                    // console.log(tagUid[i]);  
                                    cmd.push(tagUid[i]);  
                                }  
                                cmd[10] = blockAddress & 0x0ff;  
                                cmd[11] = (blocknum - 1) & 0x0ff;  
                                console.log(cmd);  
                                var response = tech.transceive(cmd);  
                                var str = ""  
                                for(var j in response){  
                                    // console.log(typeof response[j])  
                                    str +=this.bytesToString(response[j]);  
                                }  
                                console.log(str)  

                            }  
                        }  

                    }  
                } catch (e) {  
                    //TODO handle the exception  
                }  
            }else{  
                this.readNfc(intent)  
            }  
        },

写:

JAVA参考代码

 public void writeNfcV(View view) {  
        System.out.println("进入writeNfcV方法");  
        NfcV nfcV = null;  
        Intent intent = getIntent();  
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
        if (tag == null) {  
            nfcContent.append("未检测到NFC标签!");  
            return;  
        }  
        try {  
            nfcV = NfcV.get(tag);  
            nfcV.connect();  
            System.out.println("最大字节数:"+nfcV.getMaxTransceiveLength());  
            byte[] ID = nfcV.getTag().getId();  
            byte[] cmd = new byte[15];  
            cmd[0] = (byte) 0x22;  
            cmd[1] = (byte) 0x21;  
            System.arraycopy(ID, 0, cmd, 2, ID.length); // UID  
            byte[] input = nfcWrite.getText().toString().getBytes();  
            int count = (input.length+3)/4;//存储block数(用户输入)  
            System.out.println("count:"+count);  
            byte[] data = new byte[(count+1)*4];  
            System.out.println("data000:"+Arrays.toString(data));  
            byte[] mark = new byte[4];  
            mark[0] = 'H';  
            mark[1] = 'J';  
            mark[2] = 'I';  
            mark[3] = (byte) count;  
            System.out.println("MARK01:"+Arrays.toString(mark));  
            System.arraycopy(mark,0,data,0,4);  
            System.out.println("DATA01:"+Arrays.toString(data));  
            System.arraycopy(input,0,data,4,input.length);  
            System.out.println("DATA02:"+Arrays.toString(data));  
            for (int i = 0; i < count+1; i++) {  
                cmd[10] = (byte)(i & 0x0ff);  
                System.arraycopy(data, i*4, cmd, 11, 4);  
                byte[] rsp = nfcV.transceive(cmd);  
                if(rsp[0] == 0x00 && i==count) {  
                    Toast.makeText(this, "已成功写入数据!", Toast.LENGTH_LONG).show();  
                }  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }finally {  
            try {  
                if(nfcV != null) {  
                    nfcV.close();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }

JS实现代码

__writeNfcV(intent) {  
                try {  
                    waiting = plus.nativeUI.showWaiting('请将NFC标签靠近!');  
                    waiting.setTitle('请勿移开标签\n正在写入...');  
                    // var text = document.getElementById('text').value;  
                    console.log('text=' + this.writeCode);  
                    var textBytes = plus.android.invoke(this.writeCode, 'getBytes');  
                    var textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, plus.android.invoke('text/plain', 'getBytes'), plus.android  
                        .invoke('', 'getBytes'), textBytes);  
                    var message = new NdefMessage([textRecord]);  
                    var NfcV = plus.android.importClass('android.nfc.tech.NfcV');  
                    // var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var nfcv = NfcV.get(tag);  
                    console.log('标签格式:' + nfcv);  
                    var bytesId = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);  
                    console.log('bytesId:' + bytesId);  
                    // console.log(nfcv.getTag().getId())  
                    if (nfcv != null) {  
                        nfcv.connect();  
                        var size = nfcv.getMaxTransceiveLength();  
                        this.writeCode = '123456';//编辑内容  
                        var strVal = this.writeCode;  
                        console.log("zijie:" + this.stringToByte(strVal))  
                        var strValByte = this.stringToByte(strVal);  
                        console.log(strValByte.length)  
                        console.log('最大字节数:' + size);  
                        var cmd = [];  
                        cmd[0] = 0x22;  
                        cmd[1] = 0x21;  
                        for (var i in bytesId) {  
                            // console.log(tagUid[i]);  
                            cmd.push(bytesId[i]);  
                        }  
                        console.log(cmd);  
                        var count = parseInt(strValByte.length + 3)/4 ;//存block数  
                        console.log("count:"+count);  
                        var datav = new Array((count+1)*4);  
                        console.log("datav:"+datav)  
                        // var mark = [];  
                        // mark[0]="72"; //H  
                        // mark[1] = "74";//J  
                        // mark[2] = "73";//I  
                        // mark[3]=count;  
                        datav[0] = 72;  
                        datav[1] = 74;  
                        datav[2] = 73;  
                        datav[3] = count;  
                        // console.log("datav01:"+datav)  
                        for(var j=0;j<strValByte.length;j++){  
                            // console.log(strValByte[j]);  
                            datav[4+j] = strValByte[j]  
                        }  
                        console.log("datav02:"+datav);  
                        for(var i = 0;i<count+1;i++){  
                            cmd[10] = i&0x0ff;  
                            for(var s=0;s<4;s++){  
                                cmd[11+s] = datav[4*i+s];  
                            }  
                            // cmd[11+i]=datav[i*4+i]  

                            console.log("cmd22:"+cmd);  
                            var rsp = nfcv.transceive(cmd);  
                            console.log(rsp[0])  
                            if(rsp[0] == 0x00&& i == count){  
                                console.log('写入数据成功.');  
                                uni.showToast({  
                                    title: '写入数据成功.',  
                                    icon: 'none'  
                                });  

                            }  
                        }  

                        waiting.close();  
                        return;  

                    } else {  
                        console.log("未检测到NFCV标签");  
                        waiting.close();  
                        this.__write(intent);  
                        return;  
                    }  
                } catch (e) {  
                    console.log('error=' + e);  
                    waiting.close();  
                    uni.showToast({  
                        title: 'NFC标签写入失败,请重新贴近手机',  
                        icon: 'none'  
                    });  
                }  
            },  
stringToByte(str) {   
                var bytes = new Array();  
                var len, c;  
                len = str.length;  
                for (var i = 0; i < len; i++) {  
                    c = str.charCodeAt(i);  
                    if (c >= 0x010000 && c <= 0x10FFFF) {  
                        bytes.push(((c >> 18) & 0x07) | 0xF0);  
                        bytes.push(((c >> 12) & 0x3F) | 0x80);  
                        bytes.push(((c >> 6) & 0x3F) | 0x80);  
                        bytes.push((c & 0x3F) | 0x80);  
                    } else if (c >= 0x000800 && c <= 0x00FFFF) {  
                        bytes.push(((c >> 12) & 0x0F) | 0xE0);  
                        bytes.push(((c >> 6) & 0x3F) | 0x80);  
                        bytes.push((c & 0x3F) | 0x80);  
                    } else if (c >= 0x000080 && c <= 0x0007FF) {  
                        bytes.push(((c >> 6) & 0x1F) | 0xC0);  
                        bytes.push((c & 0x3F) | 0x80);  
                    } else {  
                        bytes.push(c & 0xFF);  
                    }  
                }  
                return bytes;  

            },

ps:
写的时候被自己蠢到了,java btye[]浪费了写时间,结果在最简单的w3c文档中看到byte在js中属于number。

继续阅读 »

需求:

在实现了可读写nfc(ndef)标签后,需要兼容另一个标签格式nfcv。

uniapp下nfc如果没有读到参考 uniapp 实现 NFC标签读取 和 写入

读:

java参考代码

private void readNfcv(Tag tag) {  
        System.out.println("进入readNfcv方法");  
        NfcV tech = NfcV.get(tag);  
        if (tech != null) {  
            try {  
                tech.connect();  
                if (tech.isConnected()) {  
                    byte[] tagUid = tag.getId();  
                    System.out.println("ceshi00000:"+tagUid);  
                    // store tag UID for use in addressed commands  
                    //读第一个block  
                    byte[] read = new byte[]{  
                            (byte) 0x22,  // FLAGS  
                            (byte) 0x23,  // 20-READ_SINGLE_BLOCK,23-所有块  
                            0, 0, 0, 0, 0, 0, 0, 0,  
                            0, 0  
                    };  
                    System.out.println("ceshi:"+read);  
                    System.arraycopy(tagUid, 0, read, 2, tagUid.length);  // paste tag UID into command  
                    byte[] res = tech.transceive(read);  
                    System.out.println("2222222:"+res);  
                    if (res != null) {  
                        System.out.println("标记:"+ Arrays.toString(res));  
                        //nfcContent.append("NfcV: " + new String(res, Charset.forName("utf-8")));  
                        if(res[1] == 'H'&& res[2] =='J' && res[3] == 'I'){  
                            int blockAddress = 1;  
                            int blocknum = res[4];  
                            byte[] cmd = new byte[]{  
                                    (byte) 0x22,  // FLAGS  
                                    (byte) 0x23,  // 20-READ_SINGLE_BLOCK,23-所有块  
                                    0, 0, 0, 0, 0, 0, 0, 0,  
                                    (byte) (blockAddress & 0x0ff), (byte) (blocknum - 1 & 0x0ff)  
                            };  
                            System.arraycopy(tagUid, 0, cmd, 2, tagUid.length);  // paste tag UID into command  
                            byte[] response = tech.transceive(cmd);  
                            System.out.println("主要数据"+Arrays.toString(response));  
                            if (response != null) {  
                                nfcContent.append("NfcV: " + new String(response, Charset.forName("utf-8")));  
                            }  
                        }  
                    }  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }finally {  
                try {  
                    tech.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }

js实现代码:

        readNfcV(intent) {  
            var NfcV = plus.android.importClass('android.nfc.tech.NfcV');  
            var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
            // console.log(tag);  
            console.log(NfcV.get(tag));  
            var tech = NfcV.get(tag);  
            if (tech != null) {  
                try {  
                    tech.connect();  
                    console.log(tech.isConnected());  
                    if (tech.isConnected()) {  
                        console.log('卡片字节数组ID:' + tag.getId());  
                        var tagUid = tag.getId();  
                        var buffer = [];  
                        buffer[0] = 0x22;  
                        buffer[1] = 0x23;  
                        for (var i in tagUid) {  
                            // console.log(tagUid[i]);  
                            buffer.push(tagUid[i]);  
                        }  
                        buffer[10] = 0;  
                        buffer[11] = 0;  
                        console.log(buffer);  
                        var res = tech.transceive(buffer);  
                        if (res != null) {  
                            console.log('标记:' + res);  
                            if (String.fromCharCode(res[1]) == 'H' && String.fromCharCode(res[2]) == 'J' && String.fromCharCode(res[3]) == 'I') {  
                                var blockAddress = 1;  
                                var blocknum = res[4];  
                                var cmd = [];  
                                cmd[0] = 0x22;  
                                cmd[1] = 0x23;  
                                for (var i in tagUid) {  
                                    // console.log(tagUid[i]);  
                                    cmd.push(tagUid[i]);  
                                }  
                                cmd[10] = blockAddress & 0x0ff;  
                                cmd[11] = (blocknum - 1) & 0x0ff;  
                                console.log(cmd);  
                                var response = tech.transceive(cmd);  
                                var str = ""  
                                for(var j in response){  
                                    // console.log(typeof response[j])  
                                    str +=this.bytesToString(response[j]);  
                                }  
                                console.log(str)  

                            }  
                        }  

                    }  
                } catch (e) {  
                    //TODO handle the exception  
                }  
            }else{  
                this.readNfc(intent)  
            }  
        },

写:

JAVA参考代码

 public void writeNfcV(View view) {  
        System.out.println("进入writeNfcV方法");  
        NfcV nfcV = null;  
        Intent intent = getIntent();  
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
        if (tag == null) {  
            nfcContent.append("未检测到NFC标签!");  
            return;  
        }  
        try {  
            nfcV = NfcV.get(tag);  
            nfcV.connect();  
            System.out.println("最大字节数:"+nfcV.getMaxTransceiveLength());  
            byte[] ID = nfcV.getTag().getId();  
            byte[] cmd = new byte[15];  
            cmd[0] = (byte) 0x22;  
            cmd[1] = (byte) 0x21;  
            System.arraycopy(ID, 0, cmd, 2, ID.length); // UID  
            byte[] input = nfcWrite.getText().toString().getBytes();  
            int count = (input.length+3)/4;//存储block数(用户输入)  
            System.out.println("count:"+count);  
            byte[] data = new byte[(count+1)*4];  
            System.out.println("data000:"+Arrays.toString(data));  
            byte[] mark = new byte[4];  
            mark[0] = 'H';  
            mark[1] = 'J';  
            mark[2] = 'I';  
            mark[3] = (byte) count;  
            System.out.println("MARK01:"+Arrays.toString(mark));  
            System.arraycopy(mark,0,data,0,4);  
            System.out.println("DATA01:"+Arrays.toString(data));  
            System.arraycopy(input,0,data,4,input.length);  
            System.out.println("DATA02:"+Arrays.toString(data));  
            for (int i = 0; i < count+1; i++) {  
                cmd[10] = (byte)(i & 0x0ff);  
                System.arraycopy(data, i*4, cmd, 11, 4);  
                byte[] rsp = nfcV.transceive(cmd);  
                if(rsp[0] == 0x00 && i==count) {  
                    Toast.makeText(this, "已成功写入数据!", Toast.LENGTH_LONG).show();  
                }  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }finally {  
            try {  
                if(nfcV != null) {  
                    nfcV.close();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }

JS实现代码

__writeNfcV(intent) {  
                try {  
                    waiting = plus.nativeUI.showWaiting('请将NFC标签靠近!');  
                    waiting.setTitle('请勿移开标签\n正在写入...');  
                    // var text = document.getElementById('text').value;  
                    console.log('text=' + this.writeCode);  
                    var textBytes = plus.android.invoke(this.writeCode, 'getBytes');  
                    var textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, plus.android.invoke('text/plain', 'getBytes'), plus.android  
                        .invoke('', 'getBytes'), textBytes);  
                    var message = new NdefMessage([textRecord]);  
                    var NfcV = plus.android.importClass('android.nfc.tech.NfcV');  
                    // var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var nfcv = NfcV.get(tag);  
                    console.log('标签格式:' + nfcv);  
                    var bytesId = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);  
                    console.log('bytesId:' + bytesId);  
                    // console.log(nfcv.getTag().getId())  
                    if (nfcv != null) {  
                        nfcv.connect();  
                        var size = nfcv.getMaxTransceiveLength();  
                        this.writeCode = '123456';//编辑内容  
                        var strVal = this.writeCode;  
                        console.log("zijie:" + this.stringToByte(strVal))  
                        var strValByte = this.stringToByte(strVal);  
                        console.log(strValByte.length)  
                        console.log('最大字节数:' + size);  
                        var cmd = [];  
                        cmd[0] = 0x22;  
                        cmd[1] = 0x21;  
                        for (var i in bytesId) {  
                            // console.log(tagUid[i]);  
                            cmd.push(bytesId[i]);  
                        }  
                        console.log(cmd);  
                        var count = parseInt(strValByte.length + 3)/4 ;//存block数  
                        console.log("count:"+count);  
                        var datav = new Array((count+1)*4);  
                        console.log("datav:"+datav)  
                        // var mark = [];  
                        // mark[0]="72"; //H  
                        // mark[1] = "74";//J  
                        // mark[2] = "73";//I  
                        // mark[3]=count;  
                        datav[0] = 72;  
                        datav[1] = 74;  
                        datav[2] = 73;  
                        datav[3] = count;  
                        // console.log("datav01:"+datav)  
                        for(var j=0;j<strValByte.length;j++){  
                            // console.log(strValByte[j]);  
                            datav[4+j] = strValByte[j]  
                        }  
                        console.log("datav02:"+datav);  
                        for(var i = 0;i<count+1;i++){  
                            cmd[10] = i&0x0ff;  
                            for(var s=0;s<4;s++){  
                                cmd[11+s] = datav[4*i+s];  
                            }  
                            // cmd[11+i]=datav[i*4+i]  

                            console.log("cmd22:"+cmd);  
                            var rsp = nfcv.transceive(cmd);  
                            console.log(rsp[0])  
                            if(rsp[0] == 0x00&& i == count){  
                                console.log('写入数据成功.');  
                                uni.showToast({  
                                    title: '写入数据成功.',  
                                    icon: 'none'  
                                });  

                            }  
                        }  

                        waiting.close();  
                        return;  

                    } else {  
                        console.log("未检测到NFCV标签");  
                        waiting.close();  
                        this.__write(intent);  
                        return;  
                    }  
                } catch (e) {  
                    console.log('error=' + e);  
                    waiting.close();  
                    uni.showToast({  
                        title: 'NFC标签写入失败,请重新贴近手机',  
                        icon: 'none'  
                    });  
                }  
            },  
stringToByte(str) {   
                var bytes = new Array();  
                var len, c;  
                len = str.length;  
                for (var i = 0; i < len; i++) {  
                    c = str.charCodeAt(i);  
                    if (c >= 0x010000 && c <= 0x10FFFF) {  
                        bytes.push(((c >> 18) & 0x07) | 0xF0);  
                        bytes.push(((c >> 12) & 0x3F) | 0x80);  
                        bytes.push(((c >> 6) & 0x3F) | 0x80);  
                        bytes.push((c & 0x3F) | 0x80);  
                    } else if (c >= 0x000800 && c <= 0x00FFFF) {  
                        bytes.push(((c >> 12) & 0x0F) | 0xE0);  
                        bytes.push(((c >> 6) & 0x3F) | 0x80);  
                        bytes.push((c & 0x3F) | 0x80);  
                    } else if (c >= 0x000080 && c <= 0x0007FF) {  
                        bytes.push(((c >> 6) & 0x1F) | 0xC0);  
                        bytes.push((c & 0x3F) | 0x80);  
                    } else {  
                        bytes.push(c & 0xFF);  
                    }  
                }  
                return bytes;  

            },

ps:
写的时候被自己蠢到了,java btye[]浪费了写时间,结果在最简单的w3c文档中看到byte在js中属于number。

收起阅读 »

iOS平台配置应用使用广告标识(IDFA)

iOS IDFA

此文档将不再维护,请参考新文档:https://uniapp.dcloud.io/tutorial/app-ios-idfa

HBuilderX 3.2.9+ 版本已适配 iOS15 请更新

  • 将 HX 升级到 3.2.9 及以上版本,建议使用最新的版本;
  • 如果项目是通过 cli 创建的需要将依赖也升级到新版本;

概述

12年9月份iOS6发布,IDFA面世,主要用于给开发者跟踪应用中广告的投放效果,但很多应用(或三方SDK)会获取IDFA作为设备唯一标识使用。
iOS14.5 发布之后,苹果要求应用获取 IDFA 时,需弹出用户许可收集跟踪数据的授权框,如果没有弹出授权框则可能会被App Store审核拒绝,提示违反5.1.2规则:

Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing  

We noticed you do not use App Tracking Transparency to request the user's permission before tracking their activity across apps and websites. The app privacy information you provided in App Store Connect indicates you collect data in order to track the user, including Device ID and Precise Location.  

Starting with iOS 14.5, apps on the App Store need to receive the user’s permission through the AppTrackingTransparency framework before collecting data used to track them. This requirement protects the privacy of App Store users.  

Next Steps  

Here are two ways to resolve this issue:  

- You can remove the tracking functionality from your app and update your app privacy information in App Store Connect.  
- If you decide to continue tracking users, you must implement App Tracking Transparency and request permission before collecting data used to track the user or device.  

Resources  

- See Frequently Asked Questions about the new requirements for apps that track users.  
- Learn more about designing appropriate permission requests.

请使用 HBuilderX 3.2.9+ 版本,按照下面步骤配置开启广告标识(IDFA),重新打包提交审核`

如何判断是否需要开启广告标识(IDFA)?

1.只要您的应用使用了uni-AD广告模块,就需要开启 IDFA;
2.使用的 HX 版本低于 3.2.15 版本并且应用使用了新浪微博登录和分享、一键登录、友盟统计 其中一个或多个功能模块,这些SDK内会触发获取IDFA,所以需要开启 IDFA (注:HX 3.2.15及以上版本更新了这些三方SDK,不在获取IDFA)

一些uni原生插件也可能会读取IDFA,因此碰到App Store审核不通过,提示违反5.1.2规则且内容中包含App Tracking Transparency都可以通过配置开启广告标识(IDFA)解决。

uni-AD中的广告基础功能并不会访问IDFA,没有勾选三方广告SDK时不需要访问开启广告标识(IDFA)
注:对于非广告类的三方SDK,我们会密切关注其官方的版本更新,待官方出了不包含IDFA的版本我们会尽快适配升级

配置开启广告标识(IDFA)

在 manifest.json 文件的 “App常用其它设置” 中可勾选开启(注意HBuilder X 2.4以上为默认勾选),需提交云端打包才会生效

配置 NSUserTrackingUsageDescription 隐私描述
开启广告标识(IDFA)后,云端打包默认隐私描述为“请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验”,也可以在 manifest.json 文件的 “App权限配置” 项的“iOS隐私信息访问的许可描述”下配置 NSUserTrackingUsageDescription 隐私描述:

注:使用低版本HBuilderX时可以切换到manifest.json的源码视图,手动在"privacyDescription"节点下添加 NSUserTrackingUsageDescription 字段配置隐私描述。

隐私描述是为了告诉用户,应用为什么要跟踪用户及访问设备的IDFA,配置的描述内容会展示在授权框上,参考以下建议描述说明:

  • 包含uni-AD功能时填写: 请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备、第三方广告、并保障服务安全与提示浏览体验
  • 不包含uni-AD功能时填写:请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验

运行时弹出授权提示框显示效果如下:

配置 “App 隐私”

开启广告标识(IDFA)后,提交App Store审核之前,需要在App Store Connect 配置 “App 隐私”。
首先点击编辑“数据类型”,勾选 “是,我们会从此App收集数据” 选项;然后点下一步,


因为uni框架会收集崩溃数据,所以需要勾选列表中的“崩溃数据”选项,另外再勾选“设备 ID”选项;
如果您使用了uni-AD,则勾选“广告数据”选项,如果没有,则不勾选;
如下图所示,然后发布。

注意:编辑“数据类型”时,需根据自己应用使用到的数据,灵活勾选;比如使用了定位,则勾选定位相关的选项
再编辑“设备 ID” (如使用了uni-AD则再勾选“第三方广告”选项)

编辑“崩溃数据”

编辑“广告数据”(如果上一步勾选了)

完成界面

代码中如何获取IDFA标识

plus.device.getInfo({//需要勾选IDFA  
    success:function(e){  
        console.log('idfa =  '+JSON.stringify(e.idfa));  
    },  
    fail:function(e){  
        console.log('getDeviceInfo failed: '+JSON.stringify(e));  
    }  
});

也可通过native.js获取:

var idfa = '';  
var manager = plus.ios.invoke('ASIdentifierManager', 'sharedManager');  
if(plus.ios.invoke(manager, 'isAdvertisingTrackingEnabled')){  
    var identifier = plus.ios.invoke(manager, 'advertisingIdentifier');  
    idfa = plus.ios.invoke(identifier, 'UUIDString');  
    plus.ios.deleteObject(identifier);  
}  
plus.ios.deleteObject(manager);  
console.log('idfa = '+idfa);

参考Uni插件示例:https://ext.dcloud.net.cn/plugin?id=726

5+SDK离线打包

配置参考文档:https://nativesupport.dcloud.net.cn/AppDocs/usesdk/ios

注意事项

配置NSUserTrackingUsageDescription仍然审核不通过,提示违反5.1.1规则:

如果配置了开启广告标识(IDFA)并且也配置了 NSUserTrackingUsageDescription隐私描述,但是应用还是被App Stroe审核拒绝,且提示违反5.1.1规则:

Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage    

We noticed that your app requests the user's consent to access the AppTrackingTransparency framework, but doesn't sufficiently explain the use of the AppTrackingTransparency framework in the purpose string.  

To help users make informed decisions about how their data is used, all permission request alerts need to specify how your app will use the requested information.    

Next Steps    

Please revise the relevant purpose string in your app's Info.plist file to specify why your app needs access to the user's AppTrackingTransparency framework.  

You can modify your app's Info.plist file using the property list editor in Xcode.  

Resources    

- See example of helpful, informative purpose strings.  
- Review a list of relevant property list keys.

则可能是描述内容过于简单,没有准确说明应用为什么要跟踪用户及访问设备的IDFA,可参考上文的建议更新NSUserTrackingUsageDescription描述内容

配置NSUserTrackingUsageDescription仍然审核不通过,提示违反2.1规则:

如果配置了开启广告标识(IDFA)并且也配置了 NSUserTrackingUsageDescription隐私描述,但是应用还是被App Stroe审核拒绝,且提示违反2.1规则:

Guideline 2.1 - Information Needed  

We're looking forward to completing the review of your app, but we need more information to continue. Specifically, we noticed that your app uses the AppTrackingTransparency framework, but we haven't been able to locate the App Tracking Transparency permission request.  

Next Steps  

Please indicate where in your app we can find the AppTrackingTransparency permission request. The request should appear before any data is collected that could be used to track the user.  

Apps that track user's activity must implement App Tracking Transparency and request permission before collecting data used to track.  

Resources  

See Frequently Asked Questions about the new requirements for apps that track users.  

Since your App Store Connect status is Metadata Rejected, we do NOT require a new binary. To revise the metadata, visit App Store Connect to select your app and revise the desired metadata values. Once you’ve completed all changes, reply to this message in Resolution Center and we will continue the review.

则可能是App Store Connect配置 “App 隐私”的选项不对,请参考上文重新 配置 “App 隐私”中的选项。

配置NSUserTrackingUsageDescription后真机运行不弹出授权提示框

如果按照上述描述勾选了IDFA 和配置了NSUserTrackingUsageDescription隐私描述,但是真机运行App启动时没有弹出授权提示框,可能的原因是,手机的系统版本是iOS14以下的,或者是iOS14.5的手机,但是手机“设置-隐私-跟踪”里,系统默认将“跟踪选项”关闭了且灰色不可设置;目前这种情况还不确定是iOS的bug,还是是针对地区特殊对待,解决办法:可以将账号切换成一个美区的,这时“跟踪选项”是可以操作的;或者将手机设置还原成默认设置,这时App启动时也能弹出授权提示框,但只会弹出一次。

继续阅读 »

此文档将不再维护,请参考新文档:https://uniapp.dcloud.io/tutorial/app-ios-idfa

HBuilderX 3.2.9+ 版本已适配 iOS15 请更新

  • 将 HX 升级到 3.2.9 及以上版本,建议使用最新的版本;
  • 如果项目是通过 cli 创建的需要将依赖也升级到新版本;

概述

12年9月份iOS6发布,IDFA面世,主要用于给开发者跟踪应用中广告的投放效果,但很多应用(或三方SDK)会获取IDFA作为设备唯一标识使用。
iOS14.5 发布之后,苹果要求应用获取 IDFA 时,需弹出用户许可收集跟踪数据的授权框,如果没有弹出授权框则可能会被App Store审核拒绝,提示违反5.1.2规则:

Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing  

We noticed you do not use App Tracking Transparency to request the user's permission before tracking their activity across apps and websites. The app privacy information you provided in App Store Connect indicates you collect data in order to track the user, including Device ID and Precise Location.  

Starting with iOS 14.5, apps on the App Store need to receive the user’s permission through the AppTrackingTransparency framework before collecting data used to track them. This requirement protects the privacy of App Store users.  

Next Steps  

Here are two ways to resolve this issue:  

- You can remove the tracking functionality from your app and update your app privacy information in App Store Connect.  
- If you decide to continue tracking users, you must implement App Tracking Transparency and request permission before collecting data used to track the user or device.  

Resources  

- See Frequently Asked Questions about the new requirements for apps that track users.  
- Learn more about designing appropriate permission requests.

请使用 HBuilderX 3.2.9+ 版本,按照下面步骤配置开启广告标识(IDFA),重新打包提交审核`

如何判断是否需要开启广告标识(IDFA)?

1.只要您的应用使用了uni-AD广告模块,就需要开启 IDFA;
2.使用的 HX 版本低于 3.2.15 版本并且应用使用了新浪微博登录和分享、一键登录、友盟统计 其中一个或多个功能模块,这些SDK内会触发获取IDFA,所以需要开启 IDFA (注:HX 3.2.15及以上版本更新了这些三方SDK,不在获取IDFA)

一些uni原生插件也可能会读取IDFA,因此碰到App Store审核不通过,提示违反5.1.2规则且内容中包含App Tracking Transparency都可以通过配置开启广告标识(IDFA)解决。

uni-AD中的广告基础功能并不会访问IDFA,没有勾选三方广告SDK时不需要访问开启广告标识(IDFA)
注:对于非广告类的三方SDK,我们会密切关注其官方的版本更新,待官方出了不包含IDFA的版本我们会尽快适配升级

配置开启广告标识(IDFA)

在 manifest.json 文件的 “App常用其它设置” 中可勾选开启(注意HBuilder X 2.4以上为默认勾选),需提交云端打包才会生效

配置 NSUserTrackingUsageDescription 隐私描述
开启广告标识(IDFA)后,云端打包默认隐私描述为“请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验”,也可以在 manifest.json 文件的 “App权限配置” 项的“iOS隐私信息访问的许可描述”下配置 NSUserTrackingUsageDescription 隐私描述:

注:使用低版本HBuilderX时可以切换到manifest.json的源码视图,手动在"privacyDescription"节点下添加 NSUserTrackingUsageDescription 字段配置隐私描述。

隐私描述是为了告诉用户,应用为什么要跟踪用户及访问设备的IDFA,配置的描述内容会展示在授权框上,参考以下建议描述说明:

  • 包含uni-AD功能时填写: 请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备、第三方广告、并保障服务安全与提示浏览体验
  • 不包含uni-AD功能时填写:请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验

运行时弹出授权提示框显示效果如下:

配置 “App 隐私”

开启广告标识(IDFA)后,提交App Store审核之前,需要在App Store Connect 配置 “App 隐私”。
首先点击编辑“数据类型”,勾选 “是,我们会从此App收集数据” 选项;然后点下一步,


因为uni框架会收集崩溃数据,所以需要勾选列表中的“崩溃数据”选项,另外再勾选“设备 ID”选项;
如果您使用了uni-AD,则勾选“广告数据”选项,如果没有,则不勾选;
如下图所示,然后发布。

注意:编辑“数据类型”时,需根据自己应用使用到的数据,灵活勾选;比如使用了定位,则勾选定位相关的选项
再编辑“设备 ID” (如使用了uni-AD则再勾选“第三方广告”选项)

编辑“崩溃数据”

编辑“广告数据”(如果上一步勾选了)

完成界面

代码中如何获取IDFA标识

plus.device.getInfo({//需要勾选IDFA  
    success:function(e){  
        console.log('idfa =  '+JSON.stringify(e.idfa));  
    },  
    fail:function(e){  
        console.log('getDeviceInfo failed: '+JSON.stringify(e));  
    }  
});

也可通过native.js获取:

var idfa = '';  
var manager = plus.ios.invoke('ASIdentifierManager', 'sharedManager');  
if(plus.ios.invoke(manager, 'isAdvertisingTrackingEnabled')){  
    var identifier = plus.ios.invoke(manager, 'advertisingIdentifier');  
    idfa = plus.ios.invoke(identifier, 'UUIDString');  
    plus.ios.deleteObject(identifier);  
}  
plus.ios.deleteObject(manager);  
console.log('idfa = '+idfa);

参考Uni插件示例:https://ext.dcloud.net.cn/plugin?id=726

5+SDK离线打包

配置参考文档:https://nativesupport.dcloud.net.cn/AppDocs/usesdk/ios

注意事项

配置NSUserTrackingUsageDescription仍然审核不通过,提示违反5.1.1规则:

如果配置了开启广告标识(IDFA)并且也配置了 NSUserTrackingUsageDescription隐私描述,但是应用还是被App Stroe审核拒绝,且提示违反5.1.1规则:

Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage    

We noticed that your app requests the user's consent to access the AppTrackingTransparency framework, but doesn't sufficiently explain the use of the AppTrackingTransparency framework in the purpose string.  

To help users make informed decisions about how their data is used, all permission request alerts need to specify how your app will use the requested information.    

Next Steps    

Please revise the relevant purpose string in your app's Info.plist file to specify why your app needs access to the user's AppTrackingTransparency framework.  

You can modify your app's Info.plist file using the property list editor in Xcode.  

Resources    

- See example of helpful, informative purpose strings.  
- Review a list of relevant property list keys.

则可能是描述内容过于简单,没有准确说明应用为什么要跟踪用户及访问设备的IDFA,可参考上文的建议更新NSUserTrackingUsageDescription描述内容

配置NSUserTrackingUsageDescription仍然审核不通过,提示违反2.1规则:

如果配置了开启广告标识(IDFA)并且也配置了 NSUserTrackingUsageDescription隐私描述,但是应用还是被App Stroe审核拒绝,且提示违反2.1规则:

Guideline 2.1 - Information Needed  

We're looking forward to completing the review of your app, but we need more information to continue. Specifically, we noticed that your app uses the AppTrackingTransparency framework, but we haven't been able to locate the App Tracking Transparency permission request.  

Next Steps  

Please indicate where in your app we can find the AppTrackingTransparency permission request. The request should appear before any data is collected that could be used to track the user.  

Apps that track user's activity must implement App Tracking Transparency and request permission before collecting data used to track.  

Resources  

See Frequently Asked Questions about the new requirements for apps that track users.  

Since your App Store Connect status is Metadata Rejected, we do NOT require a new binary. To revise the metadata, visit App Store Connect to select your app and revise the desired metadata values. Once you’ve completed all changes, reply to this message in Resolution Center and we will continue the review.

则可能是App Store Connect配置 “App 隐私”的选项不对,请参考上文重新 配置 “App 隐私”中的选项。

配置NSUserTrackingUsageDescription后真机运行不弹出授权提示框

如果按照上述描述勾选了IDFA 和配置了NSUserTrackingUsageDescription隐私描述,但是真机运行App启动时没有弹出授权提示框,可能的原因是,手机的系统版本是iOS14以下的,或者是iOS14.5的手机,但是手机“设置-隐私-跟踪”里,系统默认将“跟踪选项”关闭了且灰色不可设置;目前这种情况还不确定是iOS的bug,还是是针对地区特殊对待,解决办法:可以将账号切换成一个美区的,这时“跟踪选项”是可以操作的;或者将手机设置还原成默认设置,这时App启动时也能弹出授权提示框,但只会弹出一次。

收起阅读 »

如何在 uniapp 项目中,使用“插件市场” 的原生插件

uniapp原生插件 插件市场 uniapp插件

插件市场 : http://ext.dcloud.net.cn/?cat1=5&cat2=51

1. 第一步: 首先在HBuilder x 中新建一个uniapp 项目,如果已建好 uniapp 项目则跳过该步骤。

第二步: 在 ”插件市场中 “ 选择你需要的原生插件 -》 选择购买 或 试用-》 弹出一个 uniapp 应用选择框,勾选你要在哪一个uniapp项目中使用该插件。

第三步: 回到HBuilder x 工程中,找到刚才 勾选中的 uniapp 项目,打开配置文件-》manifest.json -》选择“App原生插件配置” -》选择 “ 云端插件 “,弹出一个插件选择框,勾选你要使用的插件即可。

第四步: 你进行正常的云打包,就可以使用相关插件的功能, 如果你是想在本地测试使用该插件,还需要制作自定义基座,分别是android 或 ios 的,主要是把插件打包进基座里,以便可以在本地测试应用, 制作自定义基座方法, HBx 菜单栏 -》发行-》原生App 云打包-》填写好相关的证书文件后-》勾选自定义基座-》执行打包。

第五步: 等待云打包成功, 你检查 unpackage / debug 文件夹下会出一个: android_debug.apk 或者 iOS_debug.ipa 安装包,这就是测试使用的自定义基座安装包。

第六步:等自定义基座制作完成后, 在HBx 菜单栏-》运行 -》运行到手机或者模拟器-》运行基座选择-》 选择 自定义基座 即可。

第七步: 运行项目到 手机 或者 模拟器上,就可以使用该插件的功能。

第八步:根据插件相关的文档 ,使用插件相关的方法即可。

继续阅读 »

插件市场 : http://ext.dcloud.net.cn/?cat1=5&cat2=51

1. 第一步: 首先在HBuilder x 中新建一个uniapp 项目,如果已建好 uniapp 项目则跳过该步骤。

第二步: 在 ”插件市场中 “ 选择你需要的原生插件 -》 选择购买 或 试用-》 弹出一个 uniapp 应用选择框,勾选你要在哪一个uniapp项目中使用该插件。

第三步: 回到HBuilder x 工程中,找到刚才 勾选中的 uniapp 项目,打开配置文件-》manifest.json -》选择“App原生插件配置” -》选择 “ 云端插件 “,弹出一个插件选择框,勾选你要使用的插件即可。

第四步: 你进行正常的云打包,就可以使用相关插件的功能, 如果你是想在本地测试使用该插件,还需要制作自定义基座,分别是android 或 ios 的,主要是把插件打包进基座里,以便可以在本地测试应用, 制作自定义基座方法, HBx 菜单栏 -》发行-》原生App 云打包-》填写好相关的证书文件后-》勾选自定义基座-》执行打包。

第五步: 等待云打包成功, 你检查 unpackage / debug 文件夹下会出一个: android_debug.apk 或者 iOS_debug.ipa 安装包,这就是测试使用的自定义基座安装包。

第六步:等自定义基座制作完成后, 在HBx 菜单栏-》运行 -》运行到手机或者模拟器-》运行基座选择-》 选择 自定义基座 即可。

第七步: 运行项目到 手机 或者 模拟器上,就可以使用该插件的功能。

第八步:根据插件相关的文档 ,使用插件相关的方法即可。

收起阅读 »

关于uniapp原生插件打包 FileProvider冲突问题。

云打包冲突 插件 FileProvider 冲突

1、新建XXFileProvider继承自FileProvider
2、注册改为<provider android:name="xxx.xx.xx.XXFileProvider"
android:authorities="${applicationId}.xxx.fileProvider"
3、authorities不要跟主项目有冲突即可

(XX xx 表示开发者任意填写)

继续阅读 »

1、新建XXFileProvider继承自FileProvider
2、注册改为<provider android:name="xxx.xx.xx.XXFileProvider"
android:authorities="${applicationId}.xxx.fileProvider"
3、authorities不要跟主项目有冲突即可

(XX xx 表示开发者任意填写)

收起阅读 »

uni-push ,iOS 通过透传 发送通知,但手机通知知栏未显示

前提 :1、Uni Push后台 配置ok (iOS 推送p12证书)
2、通过 this.clientid=plus.push.getClientInfo().clientid 获取客户端id
3、* plus.push.createMessage(message.title,message.content);这段代码必须要有,手机通知栏才会显示通知,也就是说需要在接收消息回调里面 自己注册本地通知才会有通知栏的 ,但经过测试,使用透传方式,app在线状态会收到通知,离线收不到。

继续更新 ....目前已实现安卓、苹果在线离线接收消息。。


在App.vue 文件里 onLaunch: function () {}   方法如下  
//判断客户端  
 var clent=uni.getSystemInfoSync().platform  
plus.push.setAutoNotification(true)  
const _self = this;  
        //收到透传消息    
        //只有APP在线时,才会触发receive事件,透传消息不会触发系统消息,需要创建本地消息    
        plus.push.addEventListener("receive", function(msg) {    
            var clent=uni.getSystemInfoSync().platform  
            console.log("(receive):" + JSON.stringify(msg));    
            if (clent=='ios') { //如果是IOS    
                var payload = msg.payload;    
                //【APP离线】收到消息,但没有提醒(发生在一次收到多个离线消息时,只有一个有提醒,但其他的没有提醒)    
                //【APP在线】收到消息,不会触发系统消息,需要创建本地消息,但不能重复创建。必须加msg.type验证去除死循环                  
                if (msg.aps == null && msg.type == "receive") {     
                    var messageTitle = payload.messageTitle;    
                    var messageContent = payload.messageContent;    
                    //创建本地消息,发送的本地消息也会被receive方法接收到,但没有type属性,且aps是null    
                    plus.push.createMessage(messageContent, JSON.stringify(payload), {title: messageTitle});    
                }  
                // else{  
                //  var payload = JSON.parse(msg.payload);    
                //  plus.push.createMessage(payload.messageContent, JSON.stringify(payload.payload), {title: payload.messageTitle});    
                // }    
            }    
            if (clent=='android') {   
              //如果是Android,当APP在线时,收到透传消息不会进入系统消息,需要发送本地提醒。    
                var payload = JSON.parse(msg.content);    
                var messageTitle = payload.messageTitle;    
                var messageContent = payload.messageContent;    
                plus.push.createMessage(messageContent, msg.payload, {title: messageTitle});  
                plus.runtime.setBadgeNumber(1)  
            }    
        }, false);    

        //消息点击事件    
        //【APP在线】,收到透传消息通过,不会提醒至通知栏目,需要发送本地消息,再进行点击触发的点击事件。    
        //【APP离线】,收到离线透传消息,必须通过Java后台的Intent字符串携带payload,且符合格式才能触发click事件,格式不符合不会触发  

        plus.push.addEventListener("click", function(msg) {    
            var clent=uni.getSystemInfoSync().platform  
            console.log("(click):" + JSON.stringify(msg));    
            if (clent=='ios') { //如果是IOS    
                var payload;    
                if (msg.type == "click") { //APP离线点击包含click属性,这时payload是JSON对象    
                    payload = msg.payload;    
                } else { //APP在线,收到消息不会包含type属性,这时的payload是JSON字符串,需要转为JSON对象    
                    payload = JSON.parse(msg.payload);    
                }    
                if (payload != null || payload != undefined) {    
                    console.log("payload:"+payload)  
                    //_self.callback(payload+"");    
                    _self.setUniPush_state("1")  
                    _self.setUniPush_url(payload.payload)  
                    uni.reLaunch({  
                        url: '/pages/tabBar/index/index'  
                    })  
                }    
            }    
            if (clent=='android') { //如果是Android,收到playload均是是JSON字符串,需要转为JSON对象    
                var payload = msg.payload;    
                console.log("msg.payload:"+msg.payload)  
                if (payload != null || payload != undefined) {    
                    console.log("payload:"+payload)  
                   // _self.callback(payload+"");    
                   _self.setUniPush_state("1")  
                   _self.setUniPush_url(payload)  
                   uni.reLaunch({  
                    url: '/pages/tabBar/index/index'  
                   })  
                }    
            }    
        }, false);  

另外:在 DCloud 平台发送消息时 :注意 intent格式
intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component=io.dcloud.XXXXXX/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title=你好,这是标题;S.content=这是通知的内容,你好,这是内容。;S.payload=;end
注意:component 为你的 应用id(io.dcloud.xxx)
可以看下这个链接https://ask.dcloud.net.cn/article/36622?notification_id-760228__item_id-32878写的,我也是根据她的来写的,挺不错的

继续阅读 »

前提 :1、Uni Push后台 配置ok (iOS 推送p12证书)
2、通过 this.clientid=plus.push.getClientInfo().clientid 获取客户端id
3、* plus.push.createMessage(message.title,message.content);这段代码必须要有,手机通知栏才会显示通知,也就是说需要在接收消息回调里面 自己注册本地通知才会有通知栏的 ,但经过测试,使用透传方式,app在线状态会收到通知,离线收不到。

继续更新 ....目前已实现安卓、苹果在线离线接收消息。。


在App.vue 文件里 onLaunch: function () {}   方法如下  
//判断客户端  
 var clent=uni.getSystemInfoSync().platform  
plus.push.setAutoNotification(true)  
const _self = this;  
        //收到透传消息    
        //只有APP在线时,才会触发receive事件,透传消息不会触发系统消息,需要创建本地消息    
        plus.push.addEventListener("receive", function(msg) {    
            var clent=uni.getSystemInfoSync().platform  
            console.log("(receive):" + JSON.stringify(msg));    
            if (clent=='ios') { //如果是IOS    
                var payload = msg.payload;    
                //【APP离线】收到消息,但没有提醒(发生在一次收到多个离线消息时,只有一个有提醒,但其他的没有提醒)    
                //【APP在线】收到消息,不会触发系统消息,需要创建本地消息,但不能重复创建。必须加msg.type验证去除死循环                  
                if (msg.aps == null && msg.type == "receive") {     
                    var messageTitle = payload.messageTitle;    
                    var messageContent = payload.messageContent;    
                    //创建本地消息,发送的本地消息也会被receive方法接收到,但没有type属性,且aps是null    
                    plus.push.createMessage(messageContent, JSON.stringify(payload), {title: messageTitle});    
                }  
                // else{  
                //  var payload = JSON.parse(msg.payload);    
                //  plus.push.createMessage(payload.messageContent, JSON.stringify(payload.payload), {title: payload.messageTitle});    
                // }    
            }    
            if (clent=='android') {   
              //如果是Android,当APP在线时,收到透传消息不会进入系统消息,需要发送本地提醒。    
                var payload = JSON.parse(msg.content);    
                var messageTitle = payload.messageTitle;    
                var messageContent = payload.messageContent;    
                plus.push.createMessage(messageContent, msg.payload, {title: messageTitle});  
                plus.runtime.setBadgeNumber(1)  
            }    
        }, false);    

        //消息点击事件    
        //【APP在线】,收到透传消息通过,不会提醒至通知栏目,需要发送本地消息,再进行点击触发的点击事件。    
        //【APP离线】,收到离线透传消息,必须通过Java后台的Intent字符串携带payload,且符合格式才能触发click事件,格式不符合不会触发  

        plus.push.addEventListener("click", function(msg) {    
            var clent=uni.getSystemInfoSync().platform  
            console.log("(click):" + JSON.stringify(msg));    
            if (clent=='ios') { //如果是IOS    
                var payload;    
                if (msg.type == "click") { //APP离线点击包含click属性,这时payload是JSON对象    
                    payload = msg.payload;    
                } else { //APP在线,收到消息不会包含type属性,这时的payload是JSON字符串,需要转为JSON对象    
                    payload = JSON.parse(msg.payload);    
                }    
                if (payload != null || payload != undefined) {    
                    console.log("payload:"+payload)  
                    //_self.callback(payload+"");    
                    _self.setUniPush_state("1")  
                    _self.setUniPush_url(payload.payload)  
                    uni.reLaunch({  
                        url: '/pages/tabBar/index/index'  
                    })  
                }    
            }    
            if (clent=='android') { //如果是Android,收到playload均是是JSON字符串,需要转为JSON对象    
                var payload = msg.payload;    
                console.log("msg.payload:"+msg.payload)  
                if (payload != null || payload != undefined) {    
                    console.log("payload:"+payload)  
                   // _self.callback(payload+"");    
                   _self.setUniPush_state("1")  
                   _self.setUniPush_url(payload)  
                   uni.reLaunch({  
                    url: '/pages/tabBar/index/index'  
                   })  
                }    
            }    
        }, false);  

另外:在 DCloud 平台发送消息时 :注意 intent格式
intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component=io.dcloud.XXXXXX/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title=你好,这是标题;S.content=这是通知的内容,你好,这是内容。;S.payload=;end
注意:component 为你的 应用id(io.dcloud.xxx)
可以看下这个链接https://ask.dcloud.net.cn/article/36622?notification_id-760228__item_id-32878写的,我也是根据她的来写的,挺不错的

收起阅读 »

UNIAPP-3DTOUCH iOS平台支持3D Touch快捷菜单项

3DTouch uniapp

官方有个文章介绍,说的比较简单 对于新手来说 有些困难,而且还不是UNIAPP的教程,现在分享下 UNIAPP下使用3Dtouch

首先可以参考下官方的教程:http://ask.dcloud.net.cn/article/424?tdsourcetag=s_pctim_aiomsg

1.配置3Dtouch

打开你的UNIAPP项目,根目录下有一个 manifest.json 找到 如下节点

app-plus --> distribute ---> ios 然后在 ios 节点下插入如下代码: (具体插入什么 根据自己业务逻辑来,)

 "shortcuts": [    
        {    
            "type": "share",    
            "title": "分 享",    
            "subtitle": "分享到微信、微博、QQ",    
            "icontype": "UIApplicationShortcutIconTypeShare"    
        },    
        {    
            "type": "about",    
            "title": "关 于",    
            "subtitle": "www.dcloud.io",    
            "iconfile": "sa.png",    
            "userinfo": {    
                "key3":"value3"    
            }    
        }    
    ]

2.处理3Dtouch 菜单点击

首先打开uniapp 根目录的 APP.VUEonLaunch生命周期中插入如下代码

this.checkArguments(); // 检测启动参数 // 这是默认的监听参数 也就是应用初始化的时候监听  

// 监听后台恢复 这是利用5+的方式 处理 APP进入后台后 再进入到APP前台时参数监听  
plus.globalEvent.addEventListener('newintent', (e)=>{  
            this.checkArguments(); // 检测启动参数  
});

3. 然后在 app.vue 新增处理启动参数的代码 : checkArguments

打开app.vue -->> methods 新增如下代码:

checkArguments() {  
            console.log('Shortcut-plus.runtime.launcher: ' + plus.runtime.launcher);  
            if (plus.runtime.launcher == 'shortcut') {  
                // 通过快捷方式启动,iOS平台表示通过3D Touch快捷方式,Android平台表示通过桌面快捷方式启动  
                try {  
                    var cmd = JSON.parse(plus.runtime.arguments);  
                    console.log('Shortcut-plus.runtime.arguments: ' + plus.runtime.arguments);  
                    var type = cmd && cmd.type;  
                    // 可以自行根据type 处理 你的业务逻辑  

                    setTimeout(r => {  
                        switch (type) {  
                            case 'scan':  
                                uni.scanCode({  
                                    scanType: 'qrCode'  
                                });  
                                break;  
                            case 'search':  
                                uni.navigateTo({  
                                    url: '/pages/search/index'  
                                });  
                                break;  
                            case 'shouyi':  
                                // 我的收益  
                                break;  
                            case 'agent':  
                                // 邀请好友  
                                break;    
                        }  
                    }, 800);  

                    console.log(JSON.stringify(cmd));  
                } catch (e) {  
                    console.log('Shortcut-exception: ' + e);  
                }  
            }  
        },  
继续阅读 »

官方有个文章介绍,说的比较简单 对于新手来说 有些困难,而且还不是UNIAPP的教程,现在分享下 UNIAPP下使用3Dtouch

首先可以参考下官方的教程:http://ask.dcloud.net.cn/article/424?tdsourcetag=s_pctim_aiomsg

1.配置3Dtouch

打开你的UNIAPP项目,根目录下有一个 manifest.json 找到 如下节点

app-plus --> distribute ---> ios 然后在 ios 节点下插入如下代码: (具体插入什么 根据自己业务逻辑来,)

 "shortcuts": [    
        {    
            "type": "share",    
            "title": "分 享",    
            "subtitle": "分享到微信、微博、QQ",    
            "icontype": "UIApplicationShortcutIconTypeShare"    
        },    
        {    
            "type": "about",    
            "title": "关 于",    
            "subtitle": "www.dcloud.io",    
            "iconfile": "sa.png",    
            "userinfo": {    
                "key3":"value3"    
            }    
        }    
    ]

2.处理3Dtouch 菜单点击

首先打开uniapp 根目录的 APP.VUEonLaunch生命周期中插入如下代码

this.checkArguments(); // 检测启动参数 // 这是默认的监听参数 也就是应用初始化的时候监听  

// 监听后台恢复 这是利用5+的方式 处理 APP进入后台后 再进入到APP前台时参数监听  
plus.globalEvent.addEventListener('newintent', (e)=>{  
            this.checkArguments(); // 检测启动参数  
});

3. 然后在 app.vue 新增处理启动参数的代码 : checkArguments

打开app.vue -->> methods 新增如下代码:

checkArguments() {  
            console.log('Shortcut-plus.runtime.launcher: ' + plus.runtime.launcher);  
            if (plus.runtime.launcher == 'shortcut') {  
                // 通过快捷方式启动,iOS平台表示通过3D Touch快捷方式,Android平台表示通过桌面快捷方式启动  
                try {  
                    var cmd = JSON.parse(plus.runtime.arguments);  
                    console.log('Shortcut-plus.runtime.arguments: ' + plus.runtime.arguments);  
                    var type = cmd && cmd.type;  
                    // 可以自行根据type 处理 你的业务逻辑  

                    setTimeout(r => {  
                        switch (type) {  
                            case 'scan':  
                                uni.scanCode({  
                                    scanType: 'qrCode'  
                                });  
                                break;  
                            case 'search':  
                                uni.navigateTo({  
                                    url: '/pages/search/index'  
                                });  
                                break;  
                            case 'shouyi':  
                                // 我的收益  
                                break;  
                            case 'agent':  
                                // 邀请好友  
                                break;    
                        }  
                    }, 800);  

                    console.log(JSON.stringify(cmd));  
                } catch (e) {  
                    console.log('Shortcut-exception: ' + e);  
                }  
            }  
        },  
收起阅读 »

挂个骗子,大家以后接单小心点

mui 外包

说的很好,把源码发给他,测试没问题,就给钱,我还是太善良了,花500要做成微信的效果,真的是服了。

说的很好,把源码发给他,测试没问题,就给钱,我还是太善良了,花500要做成微信的效果,真的是服了。

nvue编译时css告警

报警

nvue支持的css,或者说weex支持的css,是web的css的子集。
很多开发者写了错误的css,但由于css运行时不报错,而导致开发者并不知情。

2.0.3起,HBuilderX新增 nvue编译时校验css合法性,对于App平台的nvue不支持的样式在控制台给予告警。
告警不影响编译结果,仍然可以正常运行。

对于公共样式,即nvue和vue复用的样式,建议通过条件编译写法分离,比如App.vue里:

<style>  
    /*  这里写nvue和vue都复用的样式 */  

    /* #ifndef APP-PLUS-NVUE */  
    /*  这里写vue专用的样式 */    
    /* #endif */  
</style>
继续阅读 »

nvue支持的css,或者说weex支持的css,是web的css的子集。
很多开发者写了错误的css,但由于css运行时不报错,而导致开发者并不知情。

2.0.3起,HBuilderX新增 nvue编译时校验css合法性,对于App平台的nvue不支持的样式在控制台给予告警。
告警不影响编译结果,仍然可以正常运行。

对于公共样式,即nvue和vue复用的样式,建议通过条件编译写法分离,比如App.vue里:

<style>  
    /*  这里写nvue和vue都复用的样式 */  

    /* #ifndef APP-PLUS-NVUE */  
    /*  这里写vue专用的样式 */    
    /* #endif */  
</style>
收起阅读 »

隐藏 scroll-view 组件的滚动条

scroll_view

App.vue 增加如下样式可以去除 scroll-view 组件的滚动条(不支持nvue页面)

::-webkit-scrollbar {  
    display: none;  
    width: 0 !important;  
    height: 0 !important;  
    -webkit-appearance: none;  
    background: transparent;  
}

注意:
iOS 13 以下的系统,当滚动区域设置了-webkit-overflow-scrolling: touch;时(必须设置,否者几乎无法滚动),::-webkit-scrollbar 相关属性会失效,iOS 13 已经修复了此Bug。

继续阅读 »

App.vue 增加如下样式可以去除 scroll-view 组件的滚动条(不支持nvue页面)

::-webkit-scrollbar {  
    display: none;  
    width: 0 !important;  
    height: 0 !important;  
    -webkit-appearance: none;  
    background: transparent;  
}

注意:
iOS 13 以下的系统,当滚动区域设置了-webkit-overflow-scrolling: touch;时(必须设置,否者几乎无法滚动),::-webkit-scrollbar 相关属性会失效,iOS 13 已经修复了此Bug。

收起阅读 »

关于官方加强第三方控件支持的建议, 增强生态和赢利模式

建议官方加强对第三方控件的支持,
比如:
1) 聚合支付
官方可以选择性合作一两家,为开发者和企业提供支持,官方可以增加赢利模式,对开发者也是一件好事,同时也会引导其他厂商加入支持.
2) IM通讯
现在的IM通讯不是很强,特别是跨端
3) 硬件厂商
比如手唛和其他蓝牙设备,选择合作厂商

这类需求强以有个专门的团队,可以与厂商分润

继续阅读 »

建议官方加强对第三方控件的支持,
比如:
1) 聚合支付
官方可以选择性合作一两家,为开发者和企业提供支持,官方可以增加赢利模式,对开发者也是一件好事,同时也会引导其他厂商加入支持.
2) IM通讯
现在的IM通讯不是很强,特别是跨端
3) 硬件厂商
比如手唛和其他蓝牙设备,选择合作厂商

这类需求强以有个专门的团队,可以与厂商分润

收起阅读 »