HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uni-app,NFC标签读取和写入网址,手机识别在浏览器中跳转

Android uniapp NFC

参考文章链接:
uniapp 实现 NFC标签读取 和 写入

背景:
最近遇到一个需求,app需要对NFC标签写入网址(比如是商品链接),然后把NFC标签贴到商品上面,用户使用手机NFC感应可以直接跳转网页(商品详情)。
过程:
首先就是想到了在Dcloud社区查找文档,阅读量最高的就是吃辣条的大妖怪写的[uniapp 实现 NFC标签读取 和 写入]这篇文章。然后直接粘贴文章的代码去运行。发现确实能写入内容了,但是手机识别NFC只能显示新标签已收集。点击显示的是text/plain,没有显示具体内容,也跳转不了网站。一开始以为是TNF类型有问题,然后就把NdefRecord.TNF_MIME_MEDIA类型改成NdefRecord. TNF_ABSOLUTE_URI,结果还是不行。反正就是对new NdefRecord里面的几个参数各种修改,最后还是不行。后面想到能不能去通过原生Android的NFC写入代码来给自己一点灵感,下面找到的是一段Android原生代码。
文档链接:Android实现NFC读写

    /**   
     * 往nfc写入数据   
     */    
    public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {    
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);    
        Ndef ndef = Ndef.get(tag);    
        ndef.connect();    
        NdefRecord ndefRecord = NdefRecord.createTextRecord(null, data);    
        NdefRecord[] records = {ndefRecord};    
        NdefMessage ndefMessage = new NdefMessage(records);    
        ndef.writeNdefMessage(ndefMessage);    
    } 

通过这段代码,我发现NdefRecord.createTextRecord就可以实现NDEF创建,不需要通过new NdefRecord。然后在uniapp中直接把new NdefRecord方法改成了NdefRecord.createTextRecord。

// 创建包含 文本 的新 NDEF 记录  
var ndefRecord = NdefRecord.createTextRecord(str);

写入成功!很激动的用手机去读取,发现现在是打开备忘录了。哎,有戏!但是和我想的还是不一样啊!NdefRecord类是不是还有别的方法呢?然后就去查阅Android文档,找到了CreateUri方法,它可以创建包含 URI 的新 NDEF 记录。文档链接:NdefRecord.CreateUri 方法
然后又把代码换成

// 创建包含 URI 的新 NDEF 记录  
var ndefRecord = NdefRecord.createUri(str);

写入成功!用手机去读取,成功识别到写入的是一个网址,点击可以直接跳转浏览器打开!大功告成!目前试了小米、华为、1加、iPhone 11和13 等机型,除了小米都是可以成功识别并跳转浏览器的。

注:通过NdefRecord.createUri写入网址一定要加https://开头。

好了,下面贴上我所有的代码,希望可以帮助到大家,也希望大家可以多多交流。(我的代码是放在pages/main/index.vue页面下的。)

<template>  
    <view class="content">  
        <view class="uni-common-mt">  
            <view class="uni-form-item uni-column">  
                <input class="uni-input" v-model="inputValue" focus placeholder="请输入NFC要写入的内容" />  
                <button type="default" @click="writeData()">写入NFC</button>  
                <button type="default" @click="readData()">读取NFC</button>  
            </view>  
        </view>  
    </view>  
</template>  

<script>  
    var NfcAdapter;  
    var NdefRecord;  
    var NdefMessage;  
    var waiting  
    var readyRead = false;  
    var readyWriteData = false;  
    var nfcAdapter, main, pendingIntent, intentFiltersArray, techListsArray, IntentFilter  

    export default {  
        data() {  
            return {  
                inputValue: '',  
                currentNFCInfo: [], //NFC 读取消息;    
                bannerShow: false,  
                remark: "",  
                message: "",  
                count: 0,  
                timestampHide: "",  
                timestampShow: ""  
            };  
        },  
        methods: {  
            listenNFCStatus() {  
                try {  
                    console.log('Init NFC...');  
                    main = plus.android.runtimeMainActivity();  
                    var Intent = plus.android.importClass('android.content.Intent');  
                    var Activity = plus.android.importClass('android.app.Activity');  
                    var PendingIntent = plus.android.importClass('android.app.PendingIntent');  
                    IntentFilter = plus.android.importClass('android.content.IntentFilter');  
                    NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');  
                    nfcAdapter = NfcAdapter.getDefaultAdapter(main);  
                    var intent = new Intent(main, main.getClass());  
                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
                    pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);  
                    var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");  
                    ndef.addDataType("*/*");  
                    intentFiltersArray = [ndef];  
                    techListsArray = [  
                        ["android.nfc.tech.IsoDep"],  
                        ["android.nfc.tech.NfcA"],  
                        ["android.nfc.tech.NfcB"],  
                        ["android.nfc.tech.NfcF"],  
                        ["android.nfc.tech.Ndef"],  
                        ["android.nfc.tech.NfcV"],  
                        ["android.nfc.tech.NdefFormatable"],  
                        ["android.nfc.tech.MifareClassic"],  
                        ["android.nfc.tech.MifareUltralight"]  
                    ];  

                } catch (e) {  
                    console.error(e);  
                }  
            },  
            handle_nfc_data() {  

                NdefRecord = plus.android.importClass("android.nfc.NdefRecord");  
                NdefMessage = plus.android.importClass("android.nfc.NdefMessage");  
                // main = plus.android.runtimeMainActivity();    
                var intent = main.getIntent();  

                console.log("action type:" + intent.getAction());  
                if ("android.nfc.action.TECH_DISCOVERED" == intent.getAction()) {  
                    if (readyRead) {  
                        this.__read(intent);  
                        readyRead = false;  
                    }  
                    if (readyWriteData) {  
                        this.__write(intent);  
                        readyWriteData = false;  
                    }  
                } else {  
                    // waiting.close();    
                    console.log("nfc读取失败")  
                    uni.showToast({  
                        title: "NFC获取失败.",  
                        icon: "none"  
                    });  
                }  
            },  
            __read(intent) {  
                try {  
                    var content = "";  
                    waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
                    waiting.setTitle('请勿移开标签\n正在读取数据...');  
                    var tag = plus.android.importClass("android.nfc.Tag");  
                    waiting.close();  
                    var Parcelable = plus.android.importClass("android.os.Parcelable");  
                    // var rawmsgs = intent.getParcelableArrayExtra("android.nfc.extra.NDEF_MESSAGES");    
                    var rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);  

                    if (rawmsgs != null && rawmsgs.length > 0) {  
                        waiting.close();  
                        console.log(JSON.stringify(rawmsgs[0]));  
                        var records = rawmsgs[0].getRecords();  
                        var result = records[0].getPayload();  
                        console.log(JSON.stringify(result))  
                        if (result != null) {  
                            var s = plus.android.newObject("java.lang.String", result);  
                            console.log(s);  
                            this.currentNFCInfo = s;  
                            uni.showModal({  
                                title: 'NFC信息',  
                                showCancel: false,  
                                content: JSON.stringify(s),  
                            });  
                        } else {  
                            this.currentNFCInfo = "";  
                        }  
                    } else {  
                        console.log("NFC获取失败");  
                        uni.showToast({  
                            title: "NFC获取失败.",  
                            icon: "none"  
                        });  
                    }  

                } catch (e) {  
                    console.log(e);  
                    console.log("NFC获取失败,丢出异常");  
                    waiting.close();  
                    uni.showToast({  
                        title: "NFC获取失败,丢出异常.",  
                        icon: "none"  
                    });  
                    //TODO handle the exception    
                }  
            },  
            readData() {  
                readyRead = true;  
                //  waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");    
                setTimeout(this.handle_nfc_data, 1000);  
            },  
            __write(intent) {  
                try {  
                    waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
                    waiting.setTitle('请勿移开标签\n正在写入...');  
                    // var textBytes = plus.android.invoke(this.inputValue, "getBytes");  
                    // var typeBytes = plus.android.invoke('text/plain', 'getBytes')  
                    // 创建 NDEF 记录    
                    // var textRecord = new NdefRecord(  
                    //  NdefRecord.TNF_MIME_MEDIA, // TNF 类型    
                    //  typeBytes, // 类型(MIME 类型)    
                    //  null, // ID(留空以自动生成)    
                    //  textBytes, // 有效负载(文本的字节表示)    
                    // );  

                    // 创建包含 URI 的新 NDEF 记录  
                    var ndefRecord = NdefRecord.createUri(this.inputValue);  

                    var message = new NdefMessage([ndefRecord]);  
                    console.log('messgae=' + message)  
                    var Ndef = plus.android.importClass('android.nfc.tech.Ndef');  
                    var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var ndef = Ndef.get(tag);  
                    if (ndef != null) {  
                        var size = message.toByteArray().length;  
                        console.log("size=" + size);  
                        ndef.connect();  
                        if (!ndef.isWritable()) {  
                            console.log("tag不允许写入");  
                            waiting.close();  
                            uni.showToast({  
                                title: "tag不允许写入.",  
                                icon: "none"  
                            });  
                            return;  
                        }  
                        if (ndef.getMaxSize() < size) {  
                            console.log("文件大小超出容量");  
                            waiting.close();  
                            uni.showToast({  
                                title: "文件大小超出容量.",  
                                icon: "none"  
                            });  
                            return;  
                        }  
                        // console.log('写入数据:' + JSON.stringify(message) + ' __TYPE__: ' + JSON.stringify(message.__TYPE__));    
                        console.log("message:" + message)  
                        ndef.writeNdefMessage(message);  

                        waiting.close();  
                        console.log("写入数据成功.");  
                        uni.showToast({  
                            title: "写入数据成功.",  
                            icon: "none"  
                        });  
                        return;  
                    } else {  
                        var format = NdefFormatable.get(tag);  
                        if (format != null) {  
                            try {  
                                format.connect();  
                                format.format(message);  
                                console.log("格式化tag并且写入message")  
                                waiting.close();  
                                return;  
                            } catch (e) {  
                                console.log("格式化tag失败.");  
                                waiting.close();  
                                uni.showToast({  
                                    title: "格式化tag失败.",  
                                    icon: "none"  
                                });  
                                return;  
                            }  
                        } else {  
                            console.log("Tag不支持NDEF");  
                            uni.showToast({  
                                title: "Tag不支持NDEF",  
                                icon: "none"  
                            });  
                            waiting.close();  
                            return;  
                        }  
                    }  
                } catch (e) {  
                    console.log("error=" + e);  
                    waiting.close();  
                    console.log('写入失败');  
                }  
            },  
            writeData() {  
                readyWriteData = true;  
                // waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");    
                setTimeout(this.handle_nfc_data, 1000);  
            },  
        },  
        onLoad: function(option) {  
            console.log('onLoad')  
            this.listenNFCStatus()  
        },  
        onShow: function() {  
            console.log('page Show');  
            this.listenNFCStatus()  
            this.timestampShow = (new Date()).getTime();  
            console.log(this.timestampShow)  
            var TimeScale = this.timestampShow - this.timestampHide;  
            console.log(TimeScale, nfcAdapter, '134 line');  
            if (nfcAdapter == null) {  
                alert("设备不支持NFC!");  
                return;  
            }  
            if (!nfcAdapter.isEnabled()) {  
                alert("请在系统设置中先启用NFC功能!");  
                return;  
            }  
            nfcAdapter && nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
            if (this.count++ == 0) {  
                // this.listenNFCStatus()    
                return false;  
            } else if (TimeScale > 400) {  
                return false;  
            } else {  
                // this.readData();  
                // this.writeData();  
            }  
        },  
        onHide: function() {  
            console.log("onHide");  
            this.timestampHide = (new Date()).getTime();  
            console.log(this.timestampHide);  
        }  
    }  
</script>  

<style>  
    .content {  
        display: flex;  
        flex-direction: column;  
        align-items: center;  
        justify-content: center;  
    }  

    .logo {  
        height: 200rpx;  
        width: 200rpx;  
        margin-top: 200rpx;  
        margin-left: auto;  
        margin-right: auto;  
        margin-bottom: 50rpx;  
    }  

    .text-area {  
        display: flex;  
        justify-content: center;  
    }  

    .title {  
        font-size: 36rpx;  
        color: #8f8f94;  
    }  
</style>
继续阅读 »

参考文章链接:
uniapp 实现 NFC标签读取 和 写入

背景:
最近遇到一个需求,app需要对NFC标签写入网址(比如是商品链接),然后把NFC标签贴到商品上面,用户使用手机NFC感应可以直接跳转网页(商品详情)。
过程:
首先就是想到了在Dcloud社区查找文档,阅读量最高的就是吃辣条的大妖怪写的[uniapp 实现 NFC标签读取 和 写入]这篇文章。然后直接粘贴文章的代码去运行。发现确实能写入内容了,但是手机识别NFC只能显示新标签已收集。点击显示的是text/plain,没有显示具体内容,也跳转不了网站。一开始以为是TNF类型有问题,然后就把NdefRecord.TNF_MIME_MEDIA类型改成NdefRecord. TNF_ABSOLUTE_URI,结果还是不行。反正就是对new NdefRecord里面的几个参数各种修改,最后还是不行。后面想到能不能去通过原生Android的NFC写入代码来给自己一点灵感,下面找到的是一段Android原生代码。
文档链接:Android实现NFC读写

    /**   
     * 往nfc写入数据   
     */    
    public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {    
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);    
        Ndef ndef = Ndef.get(tag);    
        ndef.connect();    
        NdefRecord ndefRecord = NdefRecord.createTextRecord(null, data);    
        NdefRecord[] records = {ndefRecord};    
        NdefMessage ndefMessage = new NdefMessage(records);    
        ndef.writeNdefMessage(ndefMessage);    
    } 

通过这段代码,我发现NdefRecord.createTextRecord就可以实现NDEF创建,不需要通过new NdefRecord。然后在uniapp中直接把new NdefRecord方法改成了NdefRecord.createTextRecord。

// 创建包含 文本 的新 NDEF 记录  
var ndefRecord = NdefRecord.createTextRecord(str);

写入成功!很激动的用手机去读取,发现现在是打开备忘录了。哎,有戏!但是和我想的还是不一样啊!NdefRecord类是不是还有别的方法呢?然后就去查阅Android文档,找到了CreateUri方法,它可以创建包含 URI 的新 NDEF 记录。文档链接:NdefRecord.CreateUri 方法
然后又把代码换成

// 创建包含 URI 的新 NDEF 记录  
var ndefRecord = NdefRecord.createUri(str);

写入成功!用手机去读取,成功识别到写入的是一个网址,点击可以直接跳转浏览器打开!大功告成!目前试了小米、华为、1加、iPhone 11和13 等机型,除了小米都是可以成功识别并跳转浏览器的。

注:通过NdefRecord.createUri写入网址一定要加https://开头。

好了,下面贴上我所有的代码,希望可以帮助到大家,也希望大家可以多多交流。(我的代码是放在pages/main/index.vue页面下的。)

<template>  
    <view class="content">  
        <view class="uni-common-mt">  
            <view class="uni-form-item uni-column">  
                <input class="uni-input" v-model="inputValue" focus placeholder="请输入NFC要写入的内容" />  
                <button type="default" @click="writeData()">写入NFC</button>  
                <button type="default" @click="readData()">读取NFC</button>  
            </view>  
        </view>  
    </view>  
</template>  

<script>  
    var NfcAdapter;  
    var NdefRecord;  
    var NdefMessage;  
    var waiting  
    var readyRead = false;  
    var readyWriteData = false;  
    var nfcAdapter, main, pendingIntent, intentFiltersArray, techListsArray, IntentFilter  

    export default {  
        data() {  
            return {  
                inputValue: '',  
                currentNFCInfo: [], //NFC 读取消息;    
                bannerShow: false,  
                remark: "",  
                message: "",  
                count: 0,  
                timestampHide: "",  
                timestampShow: ""  
            };  
        },  
        methods: {  
            listenNFCStatus() {  
                try {  
                    console.log('Init NFC...');  
                    main = plus.android.runtimeMainActivity();  
                    var Intent = plus.android.importClass('android.content.Intent');  
                    var Activity = plus.android.importClass('android.app.Activity');  
                    var PendingIntent = plus.android.importClass('android.app.PendingIntent');  
                    IntentFilter = plus.android.importClass('android.content.IntentFilter');  
                    NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');  
                    nfcAdapter = NfcAdapter.getDefaultAdapter(main);  
                    var intent = new Intent(main, main.getClass());  
                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
                    pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);  
                    var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");  
                    ndef.addDataType("*/*");  
                    intentFiltersArray = [ndef];  
                    techListsArray = [  
                        ["android.nfc.tech.IsoDep"],  
                        ["android.nfc.tech.NfcA"],  
                        ["android.nfc.tech.NfcB"],  
                        ["android.nfc.tech.NfcF"],  
                        ["android.nfc.tech.Ndef"],  
                        ["android.nfc.tech.NfcV"],  
                        ["android.nfc.tech.NdefFormatable"],  
                        ["android.nfc.tech.MifareClassic"],  
                        ["android.nfc.tech.MifareUltralight"]  
                    ];  

                } catch (e) {  
                    console.error(e);  
                }  
            },  
            handle_nfc_data() {  

                NdefRecord = plus.android.importClass("android.nfc.NdefRecord");  
                NdefMessage = plus.android.importClass("android.nfc.NdefMessage");  
                // main = plus.android.runtimeMainActivity();    
                var intent = main.getIntent();  

                console.log("action type:" + intent.getAction());  
                if ("android.nfc.action.TECH_DISCOVERED" == intent.getAction()) {  
                    if (readyRead) {  
                        this.__read(intent);  
                        readyRead = false;  
                    }  
                    if (readyWriteData) {  
                        this.__write(intent);  
                        readyWriteData = false;  
                    }  
                } else {  
                    // waiting.close();    
                    console.log("nfc读取失败")  
                    uni.showToast({  
                        title: "NFC获取失败.",  
                        icon: "none"  
                    });  
                }  
            },  
            __read(intent) {  
                try {  
                    var content = "";  
                    waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
                    waiting.setTitle('请勿移开标签\n正在读取数据...');  
                    var tag = plus.android.importClass("android.nfc.Tag");  
                    waiting.close();  
                    var Parcelable = plus.android.importClass("android.os.Parcelable");  
                    // var rawmsgs = intent.getParcelableArrayExtra("android.nfc.extra.NDEF_MESSAGES");    
                    var rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);  

                    if (rawmsgs != null && rawmsgs.length > 0) {  
                        waiting.close();  
                        console.log(JSON.stringify(rawmsgs[0]));  
                        var records = rawmsgs[0].getRecords();  
                        var result = records[0].getPayload();  
                        console.log(JSON.stringify(result))  
                        if (result != null) {  
                            var s = plus.android.newObject("java.lang.String", result);  
                            console.log(s);  
                            this.currentNFCInfo = s;  
                            uni.showModal({  
                                title: 'NFC信息',  
                                showCancel: false,  
                                content: JSON.stringify(s),  
                            });  
                        } else {  
                            this.currentNFCInfo = "";  
                        }  
                    } else {  
                        console.log("NFC获取失败");  
                        uni.showToast({  
                            title: "NFC获取失败.",  
                            icon: "none"  
                        });  
                    }  

                } catch (e) {  
                    console.log(e);  
                    console.log("NFC获取失败,丢出异常");  
                    waiting.close();  
                    uni.showToast({  
                        title: "NFC获取失败,丢出异常.",  
                        icon: "none"  
                    });  
                    //TODO handle the exception    
                }  
            },  
            readData() {  
                readyRead = true;  
                //  waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");    
                setTimeout(this.handle_nfc_data, 1000);  
            },  
            __write(intent) {  
                try {  
                    waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
                    waiting.setTitle('请勿移开标签\n正在写入...');  
                    // var textBytes = plus.android.invoke(this.inputValue, "getBytes");  
                    // var typeBytes = plus.android.invoke('text/plain', 'getBytes')  
                    // 创建 NDEF 记录    
                    // var textRecord = new NdefRecord(  
                    //  NdefRecord.TNF_MIME_MEDIA, // TNF 类型    
                    //  typeBytes, // 类型(MIME 类型)    
                    //  null, // ID(留空以自动生成)    
                    //  textBytes, // 有效负载(文本的字节表示)    
                    // );  

                    // 创建包含 URI 的新 NDEF 记录  
                    var ndefRecord = NdefRecord.createUri(this.inputValue);  

                    var message = new NdefMessage([ndefRecord]);  
                    console.log('messgae=' + message)  
                    var Ndef = plus.android.importClass('android.nfc.tech.Ndef');  
                    var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var ndef = Ndef.get(tag);  
                    if (ndef != null) {  
                        var size = message.toByteArray().length;  
                        console.log("size=" + size);  
                        ndef.connect();  
                        if (!ndef.isWritable()) {  
                            console.log("tag不允许写入");  
                            waiting.close();  
                            uni.showToast({  
                                title: "tag不允许写入.",  
                                icon: "none"  
                            });  
                            return;  
                        }  
                        if (ndef.getMaxSize() < size) {  
                            console.log("文件大小超出容量");  
                            waiting.close();  
                            uni.showToast({  
                                title: "文件大小超出容量.",  
                                icon: "none"  
                            });  
                            return;  
                        }  
                        // console.log('写入数据:' + JSON.stringify(message) + ' __TYPE__: ' + JSON.stringify(message.__TYPE__));    
                        console.log("message:" + message)  
                        ndef.writeNdefMessage(message);  

                        waiting.close();  
                        console.log("写入数据成功.");  
                        uni.showToast({  
                            title: "写入数据成功.",  
                            icon: "none"  
                        });  
                        return;  
                    } else {  
                        var format = NdefFormatable.get(tag);  
                        if (format != null) {  
                            try {  
                                format.connect();  
                                format.format(message);  
                                console.log("格式化tag并且写入message")  
                                waiting.close();  
                                return;  
                            } catch (e) {  
                                console.log("格式化tag失败.");  
                                waiting.close();  
                                uni.showToast({  
                                    title: "格式化tag失败.",  
                                    icon: "none"  
                                });  
                                return;  
                            }  
                        } else {  
                            console.log("Tag不支持NDEF");  
                            uni.showToast({  
                                title: "Tag不支持NDEF",  
                                icon: "none"  
                            });  
                            waiting.close();  
                            return;  
                        }  
                    }  
                } catch (e) {  
                    console.log("error=" + e);  
                    waiting.close();  
                    console.log('写入失败');  
                }  
            },  
            writeData() {  
                readyWriteData = true;  
                // waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");    
                setTimeout(this.handle_nfc_data, 1000);  
            },  
        },  
        onLoad: function(option) {  
            console.log('onLoad')  
            this.listenNFCStatus()  
        },  
        onShow: function() {  
            console.log('page Show');  
            this.listenNFCStatus()  
            this.timestampShow = (new Date()).getTime();  
            console.log(this.timestampShow)  
            var TimeScale = this.timestampShow - this.timestampHide;  
            console.log(TimeScale, nfcAdapter, '134 line');  
            if (nfcAdapter == null) {  
                alert("设备不支持NFC!");  
                return;  
            }  
            if (!nfcAdapter.isEnabled()) {  
                alert("请在系统设置中先启用NFC功能!");  
                return;  
            }  
            nfcAdapter && nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
            if (this.count++ == 0) {  
                // this.listenNFCStatus()    
                return false;  
            } else if (TimeScale > 400) {  
                return false;  
            } else {  
                // this.readData();  
                // this.writeData();  
            }  
        },  
        onHide: function() {  
            console.log("onHide");  
            this.timestampHide = (new Date()).getTime();  
            console.log(this.timestampHide);  
        }  
    }  
</script>  

<style>  
    .content {  
        display: flex;  
        flex-direction: column;  
        align-items: center;  
        justify-content: center;  
    }  

    .logo {  
        height: 200rpx;  
        width: 200rpx;  
        margin-top: 200rpx;  
        margin-left: auto;  
        margin-right: auto;  
        margin-bottom: 50rpx;  
    }  

    .text-area {  
        display: flex;  
        justify-content: center;  
    }  

    .title {  
        font-size: 36rpx;  
        color: #8f8f94;  
    }  
</style>
收起阅读 »

个推与华为深度合作,成为首批支持兼容HarmonyOS NEXT的服务商

个推SDK 消息推送 鸿蒙next 华为


自华为官方宣布HarmonyOS NEXT鸿蒙星河版开放申请以来,越来越多的头部APP宣布启动鸿蒙原生开发,鸿蒙生态也随之进入全新发展的第二阶段。

作为华为鸿蒙生态的重要合作伙伴,个推一直积极参与鸿蒙生态建设。为帮助用户在HarmonyOS NEXT上持续享有智能互联的丰富体验,个推消息推送服务完成了对HarmonyOS NEXT的兼容适配,以支持开发者更加高效地进行鸿蒙原生应用开发。

个推消息推送SDK鸿蒙版本不仅具有高并发、高速度、高可靠等性能优势,能够有效满足APP开发者的大规模用户实时触达需求,还将面向开发者继续提供大数据标签推送、文案圈人模型等数智能力,助力开发者打造智能、友好、人性化的鸿蒙应用体验。

此外,个推也正在加快推进整体开发者服务和数智运营解决方案在鸿蒙生态中的全面落地,以更好地帮助开发者实现针对全域用户的精细化运营管理,助力APP客户的商业价值增长。

继续阅读 »


自华为官方宣布HarmonyOS NEXT鸿蒙星河版开放申请以来,越来越多的头部APP宣布启动鸿蒙原生开发,鸿蒙生态也随之进入全新发展的第二阶段。

作为华为鸿蒙生态的重要合作伙伴,个推一直积极参与鸿蒙生态建设。为帮助用户在HarmonyOS NEXT上持续享有智能互联的丰富体验,个推消息推送服务完成了对HarmonyOS NEXT的兼容适配,以支持开发者更加高效地进行鸿蒙原生应用开发。

个推消息推送SDK鸿蒙版本不仅具有高并发、高速度、高可靠等性能优势,能够有效满足APP开发者的大规模用户实时触达需求,还将面向开发者继续提供大数据标签推送、文案圈人模型等数智能力,助力开发者打造智能、友好、人性化的鸿蒙应用体验。

此外,个推也正在加快推进整体开发者服务和数智运营解决方案在鸿蒙生态中的全面落地,以更好地帮助开发者实现针对全域用户的精细化运营管理,助力APP客户的商业价值增长。

收起阅读 »

基于微信/抖音开发的开源游戏小程序源码搭建

小程序

  欢迎来到我们的代码共享网站上激动人心的 HTML5 游戏世界!此类别致力于为您提供一系列迷人的前端代码片段,直接为您的网络浏览器带来交互式游戏体验。无论您是经验丰富的开发人员还是刚刚开始编码之旅,我们的 HTML5 游戏部分都提供实时预览、分步教程和可下载链接的令人愉快的组合,以帮助您了解和创建自己的游戏项目。

  源码及演示:y.wxlbyx.icu

  安装游戏小程序源码步骤
  
  1. 下载源码:首先,您需要从开发者提供的来源下载游戏小程序的源代码。通常,这些源代码会以压缩文件的形式提供,您可以将其保存到您的计算机上的一个文件夹中。
  
  2. 解压源码:解压下载的源码压缩文件。在解压缩之后,您应该能够看到一个包含游戏小程序的文件夹。
  
  3. 配置开发环境:在安装源码之前,您需要先配置好开发环境。对于小程序开发,您需要安装微信开发者工具。您可以从微信官方网站上下载并安装该工具。
  
  4. 导入项目:打开微信开发者工具,并选择“导入项目”选项。然后,选择源码文件夹,并填写项目相关的信息,如项目名称、AppID等。
  
  5. 编译和运行:导入项目后,您可以进行编译和运行。点击工具栏中的“编译”按钮可以将源码编译成小程序,并在右侧的预览窗口中显示运行结果。
  
  6. 调试和修改:如果在编译和运行过程中出现错误或问题,您可以使用微信开发者工具提供的调试工具来查找和修复问题。可以查看开发者工具文档以了解更多关于调试和修改源码的信息。
  
  通过以上步骤,您就能够成功安装和运行游戏小程序的源码。

   

  
  结语
  
  借助 HTML5、CSS 和 JavaScript 的强大力量,我们精选的游戏展示了前端 Web 开发的创造潜力。每个代码片段都带有实时预览,让您可以直接在我们的网站上玩和体验游戏。当您沉浸在动感十足的冒险中、解决令人费解的谜题或享受经典街机游戏的怀旧时刻时,感受肾上腺素的激增。
  
  但这还不是全部!我们的 HTML5 游戏部分更进一步,为每个游戏提供详细的教程。我们相信培育学习社区,这些分步指南将引导您完成代码实现,解释所使用的逻辑和技术。无论您是想了解平台游戏中的碰撞检测如何工作,还是想了解如何创建引人入胜的动画,我们的教程都能满足您的需求。
  
  更好的是所有前端代码都可以轻松下载。您可以访问每个游戏的源代码,进行试验,并修改它以满足您的喜好。这是一个绝佳的机会,可以学习现有项目、定制它们,甚至将它们用作您自己的游戏开发之旅的起点。想象一下,你拥有创造自己迷你游戏的魔力。你可以决定角色如何移动,他们的样子,以及当你赢或输时会发生什么。

继续阅读 »

  欢迎来到我们的代码共享网站上激动人心的 HTML5 游戏世界!此类别致力于为您提供一系列迷人的前端代码片段,直接为您的网络浏览器带来交互式游戏体验。无论您是经验丰富的开发人员还是刚刚开始编码之旅,我们的 HTML5 游戏部分都提供实时预览、分步教程和可下载链接的令人愉快的组合,以帮助您了解和创建自己的游戏项目。

  源码及演示:y.wxlbyx.icu

  安装游戏小程序源码步骤
  
  1. 下载源码:首先,您需要从开发者提供的来源下载游戏小程序的源代码。通常,这些源代码会以压缩文件的形式提供,您可以将其保存到您的计算机上的一个文件夹中。
  
  2. 解压源码:解压下载的源码压缩文件。在解压缩之后,您应该能够看到一个包含游戏小程序的文件夹。
  
  3. 配置开发环境:在安装源码之前,您需要先配置好开发环境。对于小程序开发,您需要安装微信开发者工具。您可以从微信官方网站上下载并安装该工具。
  
  4. 导入项目:打开微信开发者工具,并选择“导入项目”选项。然后,选择源码文件夹,并填写项目相关的信息,如项目名称、AppID等。
  
  5. 编译和运行:导入项目后,您可以进行编译和运行。点击工具栏中的“编译”按钮可以将源码编译成小程序,并在右侧的预览窗口中显示运行结果。
  
  6. 调试和修改:如果在编译和运行过程中出现错误或问题,您可以使用微信开发者工具提供的调试工具来查找和修复问题。可以查看开发者工具文档以了解更多关于调试和修改源码的信息。
  
  通过以上步骤,您就能够成功安装和运行游戏小程序的源码。

   

  
  结语
  
  借助 HTML5、CSS 和 JavaScript 的强大力量,我们精选的游戏展示了前端 Web 开发的创造潜力。每个代码片段都带有实时预览,让您可以直接在我们的网站上玩和体验游戏。当您沉浸在动感十足的冒险中、解决令人费解的谜题或享受经典街机游戏的怀旧时刻时,感受肾上腺素的激增。
  
  但这还不是全部!我们的 HTML5 游戏部分更进一步,为每个游戏提供详细的教程。我们相信培育学习社区,这些分步指南将引导您完成代码实现,解释所使用的逻辑和技术。无论您是想了解平台游戏中的碰撞检测如何工作,还是想了解如何创建引人入胜的动画,我们的教程都能满足您的需求。
  
  更好的是所有前端代码都可以轻松下载。您可以访问每个游戏的源代码,进行试验,并修改它以满足您的喜好。这是一个绝佳的机会,可以学习现有项目、定制它们,甚至将它们用作您自己的游戏开发之旅的起点。想象一下,你拥有创造自己迷你游戏的魔力。你可以决定角色如何移动,他们的样子,以及当你赢或输时会发生什么。

收起阅读 »

【入门】uni中文

中文开发App

为满足部分业务需求,决定学习uniapp,自行学习了一段时间发现进展甚微,究其原因还是记不住各式各样的英文命令,群里的大佬告诉我说可以按照自己的想法和习惯封装一个命令库,想法很不错,于是我做了一个输入法,按照我自己的想法给命令重新做了定义(觉得可以用到各种编程工具中),奈何现实很残酷,各种命令的转译、更新等等还是不能很好的解决使用的问题(主要是没有提示,不知道命令中有哪些参数),于是趁过年这段时间不忙,决定把uniapp转成中文,毕竟成功的例子有很多(蓝茑、薇茑、UND等等,不要问为什么不用现成的,用过的人都知道为什么),反复查看这些例子的资料,最终在年前开始了!

欢迎进群学习交流:816988467

继续阅读 »

为满足部分业务需求,决定学习uniapp,自行学习了一段时间发现进展甚微,究其原因还是记不住各式各样的英文命令,群里的大佬告诉我说可以按照自己的想法和习惯封装一个命令库,想法很不错,于是我做了一个输入法,按照我自己的想法给命令重新做了定义(觉得可以用到各种编程工具中),奈何现实很残酷,各种命令的转译、更新等等还是不能很好的解决使用的问题(主要是没有提示,不知道命令中有哪些参数),于是趁过年这段时间不忙,决定把uniapp转成中文,毕竟成功的例子有很多(蓝茑、薇茑、UND等等,不要问为什么不用现成的,用过的人都知道为什么),反复查看这些例子的资料,最终在年前开始了!

欢迎进群学习交流:816988467

收起阅读 »

(已解决)关于uniapp-微信小程序-监听web-view中的postMessage无响应问题

Webview webview通信 微信小程序

按照官方给出的示例 并且添加上message事件:

<template>  
    <view>  
        <web-view :webview-styles="webviewStyles" src="https://uniapp.dcloud.io/static/web-view.html" @message="message"></web-view>  
    </view>  
</template>  

<script>  
    export default {  
        data() {  
            return {  
                webviewStyles: {  
                    progress: {  
                        color: '#FF3333'  
                    }  
                }  
            }  
        },  
methods:{  
message(data){  
console.log('我触发了')  
}  
}  
    }  
</script>

注意的是 message会在特定的时机接收到webview发送的消息(后退、组件销毁、分享),所以在H5页面发送postMessage后,在H5页面应当有后退、组件销毁、分享相关操作,那么在@message中才会调用。
于是我在H5中远程调用了uni :<script type="text/javascript" src="https://hellouniapp.dcloud.net.cn/hybrid/html/uni.webview.1.5.5.js"></script>
并且使用了postMessage

uni.postMessage({  
            data: { text:'123' }  
          });

但是在uni中却无法接收到,并且发现navigateBack等函数也无法调用,在此之后,我在uni官网查看到相关示例:https://uniapp.dcloud.net.cn/component/web-view.html#postmessage;其中有一个web-view的示例页面:


我查看该页面的源代码后(view-source:https://uniapp.dcloud.io/static/web-view.html),发现少了相关的兼容模块,在webview中的h5页面添加相关兼容sdk后,就能正常接收到消息了,如下:

var userAgent = navigator.userAgent;  
            if (userAgent.indexOf('AlipayClient') > -1) {  
                // 支付宝小程序的 JS-SDK 防止 404 需要动态加载,如果不需要兼容支付宝小程序,则无需引用此 JS 文件。  
                document.writeln('<script src="https://appx/web-view.min.js"' + '>' + '<' + '/' + 'script>');  
            } else if (/QQ/i.test(userAgent) && /miniProgram/i.test(userAgent)) {  
                // QQ 小程序  
                document.write('<script type="text/javascript" src="https://qqq.gtimg.cn/miniprogram/webview_jssdk/qqjssdk-1.0.0.js"><\/script>');  
            } else if (/miniProgram/i.test(userAgent) && /micromessenger/i.test(userAgent)) {  
                // 微信小程序 JS-SDK 如果不需要兼容微信小程序,则无需引用此 JS 文件。  
                document.write('<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"><\/script>');  
            } else if (/toutiaomicroapp/i.test(userAgent)) {  
                // 头条小程序 JS-SDK 如果不需要兼容头条小程序,则无需引用此 JS 文件。  
                document.write('<script type="text/javascript" src="https://s3.pstatp.com/toutiao/tmajssdk/jssdk-1.0.1.js"><\/script>');  
            } else if (/swan/i.test(userAgent)) {  
                // 百度小程序 JS-SDK 如果不需要兼容百度小程序,则无需引用此 JS 文件。  
                document.write('<script type="text/javascript" src="https://b.bdstatic.com/searchbox/icms/searchbox/js/swan-2.0.18.js"><\/script>');  
            } else if (/quickapp/i.test(userAgent)) {  
                // quickapp  
                document.write('<script type="text/javascript" src="https://quickapp/jssdk.webview.min.js"><\/script>');  
            }  
            if (!/toutiaomicroapp/i.test(userAgent)) {  
                document.querySelector('.post-message-section').style.visibility = 'visible';  
            }
继续阅读 »

按照官方给出的示例 并且添加上message事件:

<template>  
    <view>  
        <web-view :webview-styles="webviewStyles" src="https://uniapp.dcloud.io/static/web-view.html" @message="message"></web-view>  
    </view>  
</template>  

<script>  
    export default {  
        data() {  
            return {  
                webviewStyles: {  
                    progress: {  
                        color: '#FF3333'  
                    }  
                }  
            }  
        },  
methods:{  
message(data){  
console.log('我触发了')  
}  
}  
    }  
</script>

注意的是 message会在特定的时机接收到webview发送的消息(后退、组件销毁、分享),所以在H5页面发送postMessage后,在H5页面应当有后退、组件销毁、分享相关操作,那么在@message中才会调用。
于是我在H5中远程调用了uni :<script type="text/javascript" src="https://hellouniapp.dcloud.net.cn/hybrid/html/uni.webview.1.5.5.js"></script>
并且使用了postMessage

uni.postMessage({  
            data: { text:'123' }  
          });

但是在uni中却无法接收到,并且发现navigateBack等函数也无法调用,在此之后,我在uni官网查看到相关示例:https://uniapp.dcloud.net.cn/component/web-view.html#postmessage;其中有一个web-view的示例页面:


我查看该页面的源代码后(view-source:https://uniapp.dcloud.io/static/web-view.html),发现少了相关的兼容模块,在webview中的h5页面添加相关兼容sdk后,就能正常接收到消息了,如下:

var userAgent = navigator.userAgent;  
            if (userAgent.indexOf('AlipayClient') > -1) {  
                // 支付宝小程序的 JS-SDK 防止 404 需要动态加载,如果不需要兼容支付宝小程序,则无需引用此 JS 文件。  
                document.writeln('<script src="https://appx/web-view.min.js"' + '>' + '<' + '/' + 'script>');  
            } else if (/QQ/i.test(userAgent) && /miniProgram/i.test(userAgent)) {  
                // QQ 小程序  
                document.write('<script type="text/javascript" src="https://qqq.gtimg.cn/miniprogram/webview_jssdk/qqjssdk-1.0.0.js"><\/script>');  
            } else if (/miniProgram/i.test(userAgent) && /micromessenger/i.test(userAgent)) {  
                // 微信小程序 JS-SDK 如果不需要兼容微信小程序,则无需引用此 JS 文件。  
                document.write('<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"><\/script>');  
            } else if (/toutiaomicroapp/i.test(userAgent)) {  
                // 头条小程序 JS-SDK 如果不需要兼容头条小程序,则无需引用此 JS 文件。  
                document.write('<script type="text/javascript" src="https://s3.pstatp.com/toutiao/tmajssdk/jssdk-1.0.1.js"><\/script>');  
            } else if (/swan/i.test(userAgent)) {  
                // 百度小程序 JS-SDK 如果不需要兼容百度小程序,则无需引用此 JS 文件。  
                document.write('<script type="text/javascript" src="https://b.bdstatic.com/searchbox/icms/searchbox/js/swan-2.0.18.js"><\/script>');  
            } else if (/quickapp/i.test(userAgent)) {  
                // quickapp  
                document.write('<script type="text/javascript" src="https://quickapp/jssdk.webview.min.js"><\/script>');  
            }  
            if (!/toutiaomicroapp/i.test(userAgent)) {  
                document.querySelector('.post-message-section').style.visibility = 'visible';  
            }
收起阅读 »

vue3 + ts + pinia + uv-ui 模板项目

模板 uview vue3 uni_app
  1. 配置好vue3 + ts + pinia框架,ui库使用uview(uv-ui就是uview的vue3版本),下载项目就可以直接使用
  2. 本模板只是简单模板,里面包含 hooks|pages|components|pinia|工具类等示例代码,以及各种声明文件和ts类型配置
  3. 封装request,可以直接进行接口调用

模板插件地址

继续阅读 »
  1. 配置好vue3 + ts + pinia框架,ui库使用uview(uv-ui就是uview的vue3版本),下载项目就可以直接使用
  2. 本模板只是简单模板,里面包含 hooks|pages|components|pinia|工具类等示例代码,以及各种声明文件和ts类型配置
  3. 封装request,可以直接进行接口调用

模板插件地址

收起阅读 »

unicloud 完全放弃海外用户 !?

unicloud海外用户访问非常慢,我客户在台湾,连个图片都拉不出来
最傻的是,我想开阿里CDN,居然还要我验证bsapp.com,这是阿里自己的域名,阿里自己都搞不清楚吗?
简单来说,目前我们测试下来,别说国外了,连台湾、香港都很慢
要用这个功能的三思

unicloud海外用户访问非常慢,我客户在台湾,连个图片都拉不出来
最傻的是,我想开阿里CDN,居然还要我验证bsapp.com,这是阿里自己的域名,阿里自己都搞不清楚吗?
简单来说,目前我们测试下来,别说国外了,连台湾、香港都很慢
要用这个功能的三思

ios appstore 不更新版本的情况下,删除封面或截图

ios appstore 不更新版本的情况下,删除封面或截图,是利用appstore的漏洞
有偿提供方法

QQ:543610866,注明来历

ios appstore 不更新版本的情况下,删除封面或截图,是利用appstore的漏洞
有偿提供方法

QQ:543610866,注明来历

#插件讨论# 【 uni-pay - DCloud前端团队 】电脑微信端发起支付调用native扫码支付

在unicloud中使用uni-pay的前端组件时,如果是在电脑微信端打开h5链接,调用uni-pay前端组件发起支付时,目前会调用jsapi进行支付。

使用jsapi支付需要获取code然后换取openid,需要访问获取code的链接并重定向,而且可能会遇到code被重复使用等问题(好巧不巧我就遇到了)

但是电脑端的微信打开h5链接,其实也是一个pc浏览器的环境,在ua中可以判断,所以其实是可以调用native进行扫码支付的。

native扫码支付不需要获取code和openid,相比jsapi在开发难度上没这么麻烦,而且都是扫码支付,用native和jsapi没啥区别,那就用开发简单的native方式。

但是目前使用uni-pay前端组件在电脑微信端默认使用的jsapi,在组件上指定mode为pc也没用,最后在组件中发现了问题,将使用jssdk判断浏览器类型的方式换成使用modeCom计算属性进行判断,就可以在电脑微信端h5中调用native支付了,其余代码均不需要修改。

//在uni-pay.vue的createOrder方法中,将jsSdk.checkPlatform() === "pc"修改为this.modeCom === "pc"  
// 创建支付  
async createOrder(data = {}) {  
    let { options } = this;  
    Object.assign(options, data);  
    if (options.provider === "appleiap") {  
    // ios内购走特殊逻辑  
        return this._appleiapCreateOrder(options);  
    }  
    // #ifdef H5  
    // 判断如果是pc访问,则强制扫码模式  
    // if (jsSdk.checkPlatform() === "pc") {  
        //  options.qr_code = true;  
    // }  

    if (this.modeCom === "pc") {  
        options.qr_code = true;  
    }  
    // #endif  
    ...... // 其余代码  
}
继续阅读 »

在unicloud中使用uni-pay的前端组件时,如果是在电脑微信端打开h5链接,调用uni-pay前端组件发起支付时,目前会调用jsapi进行支付。

使用jsapi支付需要获取code然后换取openid,需要访问获取code的链接并重定向,而且可能会遇到code被重复使用等问题(好巧不巧我就遇到了)

但是电脑端的微信打开h5链接,其实也是一个pc浏览器的环境,在ua中可以判断,所以其实是可以调用native进行扫码支付的。

native扫码支付不需要获取code和openid,相比jsapi在开发难度上没这么麻烦,而且都是扫码支付,用native和jsapi没啥区别,那就用开发简单的native方式。

但是目前使用uni-pay前端组件在电脑微信端默认使用的jsapi,在组件上指定mode为pc也没用,最后在组件中发现了问题,将使用jssdk判断浏览器类型的方式换成使用modeCom计算属性进行判断,就可以在电脑微信端h5中调用native支付了,其余代码均不需要修改。

//在uni-pay.vue的createOrder方法中,将jsSdk.checkPlatform() === "pc"修改为this.modeCom === "pc"  
// 创建支付  
async createOrder(data = {}) {  
    let { options } = this;  
    Object.assign(options, data);  
    if (options.provider === "appleiap") {  
    // ios内购走特殊逻辑  
        return this._appleiapCreateOrder(options);  
    }  
    // #ifdef H5  
    // 判断如果是pc访问,则强制扫码模式  
    // if (jsSdk.checkPlatform() === "pc") {  
        //  options.qr_code = true;  
    // }  

    if (this.modeCom === "pc") {  
        options.qr_code = true;  
    }  
    // #endif  
    ...... // 其余代码  
}
收起阅读 »

Vue3组件库 Wot Design Uni v1.x版本发布新增支持支付宝、钉钉小程序平台

ui组件

介绍

一个基于Vue3+TS开发的uni-app组件库,提供60+高质量组件,支持暗黑模式、国际化和自定义主题。

特性

  • 支持 微信小程序、支付宝小程序、钉钉小程序、H5、APP 等平台.
  • 60+ 个高质量组件,覆盖移动端主流场景.
  • 使用 Typescript 构建,提供良好的组件类型系统.
  • 支持国际化,内置 6 种语言包.
  • 提供丰富的文档和组件示例.
  • 支持修改 CSS 变量实现主题定制.
  • 支持暗黑模式

地址

Github
文档网站
插件市场
QQ群

投票吧

最后,帮你最希望组件库在2024新增的功能/组件投票吧!

投票吧!

继续阅读 »

介绍

一个基于Vue3+TS开发的uni-app组件库,提供60+高质量组件,支持暗黑模式、国际化和自定义主题。

特性

  • 支持 微信小程序、支付宝小程序、钉钉小程序、H5、APP 等平台.
  • 60+ 个高质量组件,覆盖移动端主流场景.
  • 使用 Typescript 构建,提供良好的组件类型系统.
  • 支持国际化,内置 6 种语言包.
  • 提供丰富的文档和组件示例.
  • 支持修改 CSS 变量实现主题定制.
  • 支持暗黑模式

地址

Github
文档网站
插件市场
QQ群

投票吧

最后,帮你最希望组件库在2024新增的功能/组件投票吧!

投票吧!

收起阅读 »

使用 PageSpy 简化问题复现与跟踪

uniapp web_view 小程序 控制台 控制台调试 支付宝小程序 微信小程序 WebView调试

PageSpy

一款可以用来调试「Web 、H5 、WebView 、支付宝原生小程序、微信原生小程序、UniApp 小程序」等环境的平台,由货拉拉大前端开源。

它支持「实时在线调试」和「离线日志回放」两种模式,帮助大家在不同的场景下使用调试功能,全部功能都是一键启用。

我们诚挚的邀请大家在线体验,点击查看 PageSpy 调试各种框架项目

  • 仓库地址:访问 <https://github.com/HuolalaTech/page-spy-web/> ;
  • 视频教程:访问 <https://space.bilibili.com/3493272492181886>

遇到任何问题,请大家加入技术支持群讨论:查看群二维码

继续阅读 »

PageSpy

一款可以用来调试「Web 、H5 、WebView 、支付宝原生小程序、微信原生小程序、UniApp 小程序」等环境的平台,由货拉拉大前端开源。

它支持「实时在线调试」和「离线日志回放」两种模式,帮助大家在不同的场景下使用调试功能,全部功能都是一键启用。

我们诚挚的邀请大家在线体验,点击查看 PageSpy 调试各种框架项目

  • 仓库地址:访问 <https://github.com/HuolalaTech/page-spy-web/> ;
  • 视频教程:访问 <https://space.bilibili.com/3493272492181886>

遇到任何问题,请大家加入技术支持群讨论:查看群二维码

收起阅读 »

关于云打包iOS提交AppStore提示警告问题

云端打包 iOS Appstore

App Store Connect 上传要求使用 iOS 17 SDK 编译

2024年3月21号 iOS云端打包已全面升级为 XCode 15.2 和 iOS 17.2 SDK

升级XCode15.2后,需注意以下事项:

苹果在2024年2月6号发布公告要求:
从2024年4月29日开始上传 AppStore 要求使用 XCode 15 和 iOS 17 SDK 编译安装包。
公告详情:从 4 月 29 日开始生效的 App Store Connect 上传要求

目前HBuilderX云端打包iOS平台编译环境为 XCode 14.3.1 和 iOS 16.4 SDK。
因此云端打包后使用 Transporter 工具上传到 AppStore 会提示以下警告:

SDK version issue. This app was built with the iOS 16.4 SDK. Starting April 29, 2024, all iOS and iPadOS apps must be built with the iOS 17 SDK or later, included in Xcode 15 or later, in order to be uploaded to App Store Connect or submitted for distribution. (90725)

注意:此警告只是提示信息,并不影响继续提交 AppStore,开发者可继续上传并提交审核。

@2024年3月21号更新
正式版云端打包机已全面升级到 XCode 15.2 和 iOS 17.2 SDK。

@2024年3月7号更新
目前已经将Alpha版本云端打包环境升级到 XCode 15.2 和 iOS 17.2 SDK,在 Alpha 版本试运行1-2周时间。
预计在3月中将正式版云端打包机完成升级。

关于 App Store 提交的隐私更新

苹果在2024年2月29号发布公告要求:
开发者将需要在其 App 中包含隐私清单
公告详情:关于 App Store 提交的隐私更新

目前uni-app云端打包还未支持隐私清单,使用 Transporter 工具上传到 AppStore 会提示以下警告:

ITMS-91053: Missing API declaration - Your app’s code in the “HBuilder” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

注意:此警告只是提示信息,并不影响继续提交 AppStore,开发者可继续上传并提交审核。

@2024年4月24号更新
云端打包机2024年4月24号开始已经更新HBuilderX4.08正式版本支持隐私清单。
uni-app项目请更新到HBuilderX4.08及以上版本重新提交云端打包,uni-app x项目需更新到HBuilderX4.13及以上版本重新提交云端打包。详情

继续阅读 »

App Store Connect 上传要求使用 iOS 17 SDK 编译

2024年3月21号 iOS云端打包已全面升级为 XCode 15.2 和 iOS 17.2 SDK

升级XCode15.2后,需注意以下事项:

苹果在2024年2月6号发布公告要求:
从2024年4月29日开始上传 AppStore 要求使用 XCode 15 和 iOS 17 SDK 编译安装包。
公告详情:从 4 月 29 日开始生效的 App Store Connect 上传要求

目前HBuilderX云端打包iOS平台编译环境为 XCode 14.3.1 和 iOS 16.4 SDK。
因此云端打包后使用 Transporter 工具上传到 AppStore 会提示以下警告:

SDK version issue. This app was built with the iOS 16.4 SDK. Starting April 29, 2024, all iOS and iPadOS apps must be built with the iOS 17 SDK or later, included in Xcode 15 or later, in order to be uploaded to App Store Connect or submitted for distribution. (90725)

注意:此警告只是提示信息,并不影响继续提交 AppStore,开发者可继续上传并提交审核。

@2024年3月21号更新
正式版云端打包机已全面升级到 XCode 15.2 和 iOS 17.2 SDK。

@2024年3月7号更新
目前已经将Alpha版本云端打包环境升级到 XCode 15.2 和 iOS 17.2 SDK,在 Alpha 版本试运行1-2周时间。
预计在3月中将正式版云端打包机完成升级。

关于 App Store 提交的隐私更新

苹果在2024年2月29号发布公告要求:
开发者将需要在其 App 中包含隐私清单
公告详情:关于 App Store 提交的隐私更新

目前uni-app云端打包还未支持隐私清单,使用 Transporter 工具上传到 AppStore 会提示以下警告:

ITMS-91053: Missing API declaration - Your app’s code in the “HBuilder” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

注意:此警告只是提示信息,并不影响继续提交 AppStore,开发者可继续上传并提交审核。

@2024年4月24号更新
云端打包机2024年4月24号开始已经更新HBuilderX4.08正式版本支持隐私清单。
uni-app项目请更新到HBuilderX4.08及以上版本重新提交云端打包,uni-app x项目需更新到HBuilderX4.13及以上版本重新提交云端打包。详情

收起阅读 »