HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

安卓-电池优化、白名单

Native.JS

从 Android 6.0 开始,系统为了省电增加了休眠模式,系统待机一段时间后,会杀死后台正在运行的进程。但系统会有一个后台运行白名单,白名单里的应用将不会受到影响,在原生系统下,通过「设置」 - 「电池」 - 「电池优化」 - 「未优化应用」,可以看到这个白名单。

从网上查了些资料,找到:android应用申请加入电池优化白名单
根据上面资料转native.js,上代码。

  • ① 添加权限
    在manifest.json源码视图中添加<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />,就加在那一堆permissions中。

  • ② 判断我们的应用是否在白名单中

                   // 白名单  
                    var main = plus.android.runtimeMainActivity();  
                    var packName = main.getPackageName();    
                    var Context = plus.android.importClass("android.content.Context");  
                    var PowerManager = plus.android.importClass("android.os.PowerManager");  
                    // 获取电源类  
                    var pm = main.getSystemService(Context.POWER_SERVICE);  
                    console.log('是否在白名单:',pm.isIgnoringBatteryOptimizations(packName)); //是否白名单  
                    let whiteList = pm.isIgnoringBatteryOptimizations(packName);
  • ③ 调起服务

     try{  
            var Uri = plus.android.importClass("android.net.Uri");  
            var Settings = plus.android.importClass("android.provider.Settings");  
            var packageURI = Uri.parse("package:" + packName);  
            var intents = plus.android.newObject("android.content.Intent", Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,packageURI);  // 电池  
            main.startActivity(intents);   
        }catch{  
            // console.log('调起失败')  
        }
  • ④ 发行-云打包测试
    测试多次HbuliderX里是调不起来,打包后才能出来

总结:自己测试-打开应用,然后锁屏(半小时为例)
华为():仍然可以运行,收到消息
小米():中断,除了设置中的电池优化,还有应用详情的“省电策略”,需要再调试

继续阅读 »

从 Android 6.0 开始,系统为了省电增加了休眠模式,系统待机一段时间后,会杀死后台正在运行的进程。但系统会有一个后台运行白名单,白名单里的应用将不会受到影响,在原生系统下,通过「设置」 - 「电池」 - 「电池优化」 - 「未优化应用」,可以看到这个白名单。

从网上查了些资料,找到:android应用申请加入电池优化白名单
根据上面资料转native.js,上代码。

  • ① 添加权限
    在manifest.json源码视图中添加<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />,就加在那一堆permissions中。

  • ② 判断我们的应用是否在白名单中

                   // 白名单  
                    var main = plus.android.runtimeMainActivity();  
                    var packName = main.getPackageName();    
                    var Context = plus.android.importClass("android.content.Context");  
                    var PowerManager = plus.android.importClass("android.os.PowerManager");  
                    // 获取电源类  
                    var pm = main.getSystemService(Context.POWER_SERVICE);  
                    console.log('是否在白名单:',pm.isIgnoringBatteryOptimizations(packName)); //是否白名单  
                    let whiteList = pm.isIgnoringBatteryOptimizations(packName);
  • ③ 调起服务

     try{  
            var Uri = plus.android.importClass("android.net.Uri");  
            var Settings = plus.android.importClass("android.provider.Settings");  
            var packageURI = Uri.parse("package:" + packName);  
            var intents = plus.android.newObject("android.content.Intent", Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,packageURI);  // 电池  
            main.startActivity(intents);   
        }catch{  
            // console.log('调起失败')  
        }
  • ④ 发行-云打包测试
    测试多次HbuliderX里是调不起来,打包后才能出来

总结:自己测试-打开应用,然后锁屏(半小时为例)
华为():仍然可以运行,收到消息
小米():中断,除了设置中的电池优化,还有应用详情的“省电策略”,需要再调试

收起阅读 »

NFC 读取指定扇区,写入指定扇区

NFC
<script>  
let Context = plus.android.importClass('android.content.Context');  
let NfcManager = plus.android.importClass('android.nfc.NfcManager');  
let NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');  
let Settings = plus.android.importClass('android.provider.Settings');  
let Intent = plus.android.importClass('android.content.Intent');  
let Parcelable = plus.android.importClass('android.os.Parcelable');  
let PendingIntent = plus.android.importClass('android.app.PendingIntent');  
let IntentFilter = plus.android.importClass('android.content.IntentFilter');  
let NdefRecord = plus.android.importClass('android.nfc.NdefRecord');  
let NdefMessage = plus.android.importClass('android.nfc.NdefMessage');  
let Tag = plus.android.importClass('android.nfc.Tag');  
let MifareClassic = plus.android.importClass('android.nfc.tech.MifareClassic');  
let invoke = plus.android.invoke;  
export default {  
    data() {  
        return {  
            sector: 1,  
            keyType: 'A',  
            keyVal: 'FFFFFFFFFFFF', //'E58583E69C94', //'FFFFFFFFFFFF',  
            ICUID: '',  
            ICData: 'IC卡扇区数据:',  
            ICERROR: '',  
            nfcAdapter: null,  
            main: null,  
            intent: null,  
            IntervalId: null,  
            techListsArray: [  
                ['android.nfc.tech.IsoDep'],  
                ['android.nfc.tech.NfcA'],  
                ['android.nfc.tech.NfcB'],  
                ['android.nfc.tech.NfcF'],  
                ['android.nfc.tech.NfcV'],  
                ['android.nfc.tech.Ndef'],  
                ['android.nfc.tech.NdefFormatable'],  
                ['android.nfc.tech.MifareClassic'],  
                ['android.nfc.tech.MifareUltralight']  
            ]  
        };  
    },  

    created() {  
        this.nfcinit();  
    },  
    beforeDestroy() {  
        this.nfcclose();  
    },  

    methods: {  
        nfcinit() {  
            this.main = plus.android.runtimeMainActivity();  
            var nfchManager = this.main.getSystemService(Context.NFC_SERVICE);  
            var nfcAdapter = nfchManager.getDefaultAdapter();  
            if (!nfcAdapter.isEnabled()) {  
                this.intent = new Intent(Settings.ACTION_NFC_SETTINGS);  
                this.main.startActivity(this.intent);  
            }  
            var intent = new Intent(this.main, this.main.getClass());  
            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
            var pendingIntent = PendingIntent.getActivity(this.main, 0, intent, 0);  
            var ndef = new IntentFilter('android.nfc.action.TECH_DISCOVERED');  
            ndef.addDataType('*/*');  
            var intentFiltersArray = [ndef];  
            nfcAdapter.enableForegroundDispatch(this.main, pendingIntent, intentFiltersArray, this.techListsArray);  
            this.nfcAdapter = nfcAdapter;  
        },  
        nfcclose() {  
            if (this.nfcAdapter) this.nfcAdapter.disableForegroundDispatch(this.main);  
            this.nfcAdapter = null;  
            clearInterval(this.IntervalId);  
        },  
        handle_nfc_data(obj) {  
            var intent = this.main.getIntent();  
            if (intent.getAction() == 'android.nfc.action.TECH_DISCOVERED') {  
                clearInterval(this.IntervalId);  
                this.readData(intent, obj);  
            }  
        },  
        // 读扇区  请参考 https://ask.dcloud.net.cn/article/35593  
        readData(intent, obj) {  
            var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
            var techList = tag.getTechList();  
            var bisMfc = false;  
            for (var i = 0; i < techList.length; i++) {  
                if (techList[i].indexOf('MifareClassic') >= 0) {  
                    bisMfc = true;  
                    break;  
                }  
            }  
            if (!bisMfc) {  
                this.ICERROR = '卡片类型错误!';  
                return;  
            }  
            var mfc = MifareClassic.get(tag);  
            if (!mfc) {  
                this.ICERROR = '卡片获取错误!';  
                return;  
            }  
            mfc.setTimeout(3000);  
            if (!mfc.isConnected()) {  
                try {  
                    invoke(mfc, 'connect');  
                } catch (e) {  
                    this.ICERROR = '卡片连接错误!';  
                    return;  
                }  
            }  
            try {  
                this.ICUID = this.ByteArrayToHexString(tag.getId());  
                var cmdBytes = this.HexStringToByteArray(this.keyVal);  
                var auth = false;  
                //使用密钥A对扇区进行身份验证。  
                if (this.keyType == 'A') {  
                    auth = invoke(mfc, 'authenticateSectorWithKeyA', parseInt(this.sector), cmdBytes);  
                } else {  
                    //使用密钥B对扇区进行身份验证。  
                    auth = invoke(mfc, 'authenticateSectorWithKeyB', parseInt(this.sector), cmdBytes);  
                }  
                if (!auth) {  
                    this.ICERROR = '扇区验证失败';  
                    return;  
                }  
                var sectorData = [];  
                var tmpRet;  
                this.ICData = 'IC卡扇区数据>>';  
                // 调用 MifareClassic 读指定块 返回的是字节数组    
                // 若需读取扇区中的所有块  请参考 https://ask.dcloud.net.cn/article/35593  
                tmpRet = invoke(mfc, 'readBlock', 5);  
                // 此项目写入的时候有中文,用网上的字节转字符串 会出现解析乱码  
                // 所以此处导入 java String 类  
                var String = plus.android.importClass('java.lang.String');  
                // 将自己数组转换成java 字符串  
                var str = new String(tmpRet);  
                // 调用java String 类的 concat 方法 拼接一个空的字符串,不然输出str 是一个类名 plus.android.java.lang.String  

                obj.success(str.trim());  
                this.ICERROR = '读卡完成';  
            } catch (e) {  
                this.ICERROR = e.message;  
                obj.fail(e);  
            } finally {  
                mfc.close();  
            }  
        },  

        readcard(obj) {  
            var that = this;  
            (this.ICUID = ''),  
                (this.ICData = ''),  
                (this.ICERROR = ''),  
                (this.IntervalId = setInterval(function() {  
                    that.handle_nfc_data(obj);  
                }, 1000));  
        },  
        //   
        handle_nfc_write(sectorIndex, text, obj) {  
            var intent = this.main.getIntent();  
            if (intent.getAction() == 'android.nfc.action.TECH_DISCOVERED') {  

                this.write(intent, sectorIndex, text, obj);  
            }  
        },  
        //sectorIndex 扇区  
        // text 要写入的内容  
        // obj callback()  
        write(intent, sectorIndex, text, obj) {  
            try {  
                // 将要写入的内容转成字节数组  
                var textBytes = plus.android.invoke(text, 'getBytes', 'utf-8');  
                // android api参考地址  
                // https://developer.android.google.cn/reference/android/nfc/tech/MifareClassic?hl=en#writeBlock(int,%20byte[])  
                // 写入16个字节的块。不够补0  
                for (var i = textBytes.length; i < 16; i++) {  
                    textBytes.push(0);  
                }  
                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 NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                var mfc = MifareClassic.get(tag);  
                if (mfc != null) {  
                    mfc.connect();  
                    // 默认密钥  
                    var cmdBytes = this.HexStringToByteArray('FFFFFFFFFFFF');  
                    // 使用密钥A对扇区进行身份验证。  
                    let auth = mfc.authenticateSectorWithKeyA(sectorIndex, cmdBytes);  
                    // var pass = 'E58583E69C94';  
                    // var password =this.HexStringToByteArray(pass);  
                    // for (var i = password.length; i < 16; i++) {  
                    //  password.push(0);  
                    // }  
                    if (auth) {  
                        //返回给定扇区的第一个块。  
                        let block = mfc.sectorToBlock(sectorIndex);  
                        // 写入块 我们项目写在 扇区1,第2块  
                        mfc.writeBlock(block + 1, textBytes);  
                        obj.success('写卡成功');  
                        //写入密钥  
                        //mfc.writeBlock(block + 3, password);  
                        mfc.close();  
                    } else {  
                        obj.fail('认证失败');  
                    }  
                    return;  
                }  

            } catch (e) {  
                obj.fail(e);  
                console.log('error=' + e);  
            }  
        },  
        ByteArrayToHexString: function(inarray) {  
            var i, j, inn;  
            var hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];  
            var out = '';  
            for (j = 0; j < inarray.length; ++j) {  
                inn = inarray[j] & 0xff;  
                i = (inn >>> 4) & 0x0f;  
                out += hex[i];  
                i = inn & 0x0f;  
                out += hex[i];  
            }  
            return out;  
        },  
        HexStringToByteArray: function(instr) {  
            var hexA = new Array();  
            var pos = 0;  
            var len = instr.length / 2;  
            for (var i = 0; i < len; i++) {  
                var s = instr.substr(pos, 2);  
                var v = parseInt(s, 16);  
                if (v >= 128) v = v - 256;  
                hexA.push(v);  
                pos += 2;  
            }  
            return hexA;  
        }  
    }  
};  
</script>  

<style></style>
继续阅读 »
<script>  
let Context = plus.android.importClass('android.content.Context');  
let NfcManager = plus.android.importClass('android.nfc.NfcManager');  
let NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');  
let Settings = plus.android.importClass('android.provider.Settings');  
let Intent = plus.android.importClass('android.content.Intent');  
let Parcelable = plus.android.importClass('android.os.Parcelable');  
let PendingIntent = plus.android.importClass('android.app.PendingIntent');  
let IntentFilter = plus.android.importClass('android.content.IntentFilter');  
let NdefRecord = plus.android.importClass('android.nfc.NdefRecord');  
let NdefMessage = plus.android.importClass('android.nfc.NdefMessage');  
let Tag = plus.android.importClass('android.nfc.Tag');  
let MifareClassic = plus.android.importClass('android.nfc.tech.MifareClassic');  
let invoke = plus.android.invoke;  
export default {  
    data() {  
        return {  
            sector: 1,  
            keyType: 'A',  
            keyVal: 'FFFFFFFFFFFF', //'E58583E69C94', //'FFFFFFFFFFFF',  
            ICUID: '',  
            ICData: 'IC卡扇区数据:',  
            ICERROR: '',  
            nfcAdapter: null,  
            main: null,  
            intent: null,  
            IntervalId: null,  
            techListsArray: [  
                ['android.nfc.tech.IsoDep'],  
                ['android.nfc.tech.NfcA'],  
                ['android.nfc.tech.NfcB'],  
                ['android.nfc.tech.NfcF'],  
                ['android.nfc.tech.NfcV'],  
                ['android.nfc.tech.Ndef'],  
                ['android.nfc.tech.NdefFormatable'],  
                ['android.nfc.tech.MifareClassic'],  
                ['android.nfc.tech.MifareUltralight']  
            ]  
        };  
    },  

    created() {  
        this.nfcinit();  
    },  
    beforeDestroy() {  
        this.nfcclose();  
    },  

    methods: {  
        nfcinit() {  
            this.main = plus.android.runtimeMainActivity();  
            var nfchManager = this.main.getSystemService(Context.NFC_SERVICE);  
            var nfcAdapter = nfchManager.getDefaultAdapter();  
            if (!nfcAdapter.isEnabled()) {  
                this.intent = new Intent(Settings.ACTION_NFC_SETTINGS);  
                this.main.startActivity(this.intent);  
            }  
            var intent = new Intent(this.main, this.main.getClass());  
            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
            var pendingIntent = PendingIntent.getActivity(this.main, 0, intent, 0);  
            var ndef = new IntentFilter('android.nfc.action.TECH_DISCOVERED');  
            ndef.addDataType('*/*');  
            var intentFiltersArray = [ndef];  
            nfcAdapter.enableForegroundDispatch(this.main, pendingIntent, intentFiltersArray, this.techListsArray);  
            this.nfcAdapter = nfcAdapter;  
        },  
        nfcclose() {  
            if (this.nfcAdapter) this.nfcAdapter.disableForegroundDispatch(this.main);  
            this.nfcAdapter = null;  
            clearInterval(this.IntervalId);  
        },  
        handle_nfc_data(obj) {  
            var intent = this.main.getIntent();  
            if (intent.getAction() == 'android.nfc.action.TECH_DISCOVERED') {  
                clearInterval(this.IntervalId);  
                this.readData(intent, obj);  
            }  
        },  
        // 读扇区  请参考 https://ask.dcloud.net.cn/article/35593  
        readData(intent, obj) {  
            var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
            var techList = tag.getTechList();  
            var bisMfc = false;  
            for (var i = 0; i < techList.length; i++) {  
                if (techList[i].indexOf('MifareClassic') >= 0) {  
                    bisMfc = true;  
                    break;  
                }  
            }  
            if (!bisMfc) {  
                this.ICERROR = '卡片类型错误!';  
                return;  
            }  
            var mfc = MifareClassic.get(tag);  
            if (!mfc) {  
                this.ICERROR = '卡片获取错误!';  
                return;  
            }  
            mfc.setTimeout(3000);  
            if (!mfc.isConnected()) {  
                try {  
                    invoke(mfc, 'connect');  
                } catch (e) {  
                    this.ICERROR = '卡片连接错误!';  
                    return;  
                }  
            }  
            try {  
                this.ICUID = this.ByteArrayToHexString(tag.getId());  
                var cmdBytes = this.HexStringToByteArray(this.keyVal);  
                var auth = false;  
                //使用密钥A对扇区进行身份验证。  
                if (this.keyType == 'A') {  
                    auth = invoke(mfc, 'authenticateSectorWithKeyA', parseInt(this.sector), cmdBytes);  
                } else {  
                    //使用密钥B对扇区进行身份验证。  
                    auth = invoke(mfc, 'authenticateSectorWithKeyB', parseInt(this.sector), cmdBytes);  
                }  
                if (!auth) {  
                    this.ICERROR = '扇区验证失败';  
                    return;  
                }  
                var sectorData = [];  
                var tmpRet;  
                this.ICData = 'IC卡扇区数据>>';  
                // 调用 MifareClassic 读指定块 返回的是字节数组    
                // 若需读取扇区中的所有块  请参考 https://ask.dcloud.net.cn/article/35593  
                tmpRet = invoke(mfc, 'readBlock', 5);  
                // 此项目写入的时候有中文,用网上的字节转字符串 会出现解析乱码  
                // 所以此处导入 java String 类  
                var String = plus.android.importClass('java.lang.String');  
                // 将自己数组转换成java 字符串  
                var str = new String(tmpRet);  
                // 调用java String 类的 concat 方法 拼接一个空的字符串,不然输出str 是一个类名 plus.android.java.lang.String  

                obj.success(str.trim());  
                this.ICERROR = '读卡完成';  
            } catch (e) {  
                this.ICERROR = e.message;  
                obj.fail(e);  
            } finally {  
                mfc.close();  
            }  
        },  

        readcard(obj) {  
            var that = this;  
            (this.ICUID = ''),  
                (this.ICData = ''),  
                (this.ICERROR = ''),  
                (this.IntervalId = setInterval(function() {  
                    that.handle_nfc_data(obj);  
                }, 1000));  
        },  
        //   
        handle_nfc_write(sectorIndex, text, obj) {  
            var intent = this.main.getIntent();  
            if (intent.getAction() == 'android.nfc.action.TECH_DISCOVERED') {  

                this.write(intent, sectorIndex, text, obj);  
            }  
        },  
        //sectorIndex 扇区  
        // text 要写入的内容  
        // obj callback()  
        write(intent, sectorIndex, text, obj) {  
            try {  
                // 将要写入的内容转成字节数组  
                var textBytes = plus.android.invoke(text, 'getBytes', 'utf-8');  
                // android api参考地址  
                // https://developer.android.google.cn/reference/android/nfc/tech/MifareClassic?hl=en#writeBlock(int,%20byte[])  
                // 写入16个字节的块。不够补0  
                for (var i = textBytes.length; i < 16; i++) {  
                    textBytes.push(0);  
                }  
                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 NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                var mfc = MifareClassic.get(tag);  
                if (mfc != null) {  
                    mfc.connect();  
                    // 默认密钥  
                    var cmdBytes = this.HexStringToByteArray('FFFFFFFFFFFF');  
                    // 使用密钥A对扇区进行身份验证。  
                    let auth = mfc.authenticateSectorWithKeyA(sectorIndex, cmdBytes);  
                    // var pass = 'E58583E69C94';  
                    // var password =this.HexStringToByteArray(pass);  
                    // for (var i = password.length; i < 16; i++) {  
                    //  password.push(0);  
                    // }  
                    if (auth) {  
                        //返回给定扇区的第一个块。  
                        let block = mfc.sectorToBlock(sectorIndex);  
                        // 写入块 我们项目写在 扇区1,第2块  
                        mfc.writeBlock(block + 1, textBytes);  
                        obj.success('写卡成功');  
                        //写入密钥  
                        //mfc.writeBlock(block + 3, password);  
                        mfc.close();  
                    } else {  
                        obj.fail('认证失败');  
                    }  
                    return;  
                }  

            } catch (e) {  
                obj.fail(e);  
                console.log('error=' + e);  
            }  
        },  
        ByteArrayToHexString: function(inarray) {  
            var i, j, inn;  
            var hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];  
            var out = '';  
            for (j = 0; j < inarray.length; ++j) {  
                inn = inarray[j] & 0xff;  
                i = (inn >>> 4) & 0x0f;  
                out += hex[i];  
                i = inn & 0x0f;  
                out += hex[i];  
            }  
            return out;  
        },  
        HexStringToByteArray: function(instr) {  
            var hexA = new Array();  
            var pos = 0;  
            var len = instr.length / 2;  
            for (var i = 0; i < len; i++) {  
                var s = instr.substr(pos, 2);  
                var v = parseInt(s, 16);  
                if (v >= 128) v = v - 256;  
                hexA.push(v);  
                pos += 2;  
            }  
            return hexA;  
        }  
    }  
};  
</script>  

<style></style>
收起阅读 »

uniCloud admin:token不合法,请重新登录,30201,解决方案

解决方案

框架:uniCloud admin
问题:在调用增删改查功能时,老遇到token不合法的问题
原因:uni-id验证token时,默认开启了绑定设备

解决:取消绑定设备bindTokenToDevice=false

/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-id/config.json

继续阅读 »

框架:uniCloud admin
问题:在调用增删改查功能时,老遇到token不合法的问题
原因:uni-id验证token时,默认开启了绑定设备

解决:取消绑定设备bindTokenToDevice=false

/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-id/config.json

收起阅读 »

给Huilderx 一点使用建议

希望官方能把scss、less插件纳入到核心插件里面去,直接点击安装,因为使用频率比较高,而且这两款插件大部分开发者也在用。一点小小意见,望采纳

希望官方能把scss、less插件纳入到核心插件里面去,直接点击安装,因为使用频率比较高,而且这两款插件大部分开发者也在用。一点小小意见,望采纳

uni小程序SDK集成到Android后严格按官方手册仍白屏

Android

uni小程序SDK集成到Android后启动白屏

根据官方文档各种都检查了,最后发现有一个配置官方没有说但设置后解决了:

AndroidManifest.xmlapplication 节点增加属性

android:extractNativeLibs="true"

继续阅读 »

uni小程序SDK集成到Android后启动白屏

根据官方文档各种都检查了,最后发现有一个配置官方没有说但设置后解决了:

AndroidManifest.xmlapplication 节点增加属性

android:extractNativeLibs="true"

收起阅读 »

midButton的设计是不是没考虑过正常的使用情况?

一般的正常用户,在看到tabbar上有按钮时,是不是会下意识的觉得这个按钮可以点击?然而实际上,这个按钮只有在app环境下才能被绑定上事件。
这种设计,是不是有点没走脑子?既然是全平台兼容的按钮,为啥只有app上能点击?做个点击功能很难吗?

一般的正常用户,在看到tabbar上有按钮时,是不是会下意识的觉得这个按钮可以点击?然而实际上,这个按钮只有在app环境下才能被绑定上事件。
这种设计,是不是有点没走脑子?既然是全平台兼容的按钮,为啥只有app上能点击?做个点击功能很难吗?

Uniapp移动端混合开发工程师(坐标合肥)

混合开发 Vue uniapp

Uniapp移动端混合开发工程师

岗位职责:

  1. 主要负责公司APP产品、小程序、H5相关移动端开发;
  2. 具备前端性能优化经验;
  3. 根据需求认真完成相关功能的界面搭建和业务编码任务;
  4. 良好的沟通与表达能力,思路清晰,有强烈的责任心。

任职要求:
1、计算机相关专业大专及以上学历,1年以上开发经验;
2、熟练使用hbuilderx、uni-app,有参与使用uni-app开发移动端或小程序经验者优先。
3、精通JavaScript、HTML5、和CSS3编程语言,熟悉常见的UI(如:ElementUI、Ant Design Vue等)
4、熟悉ES5和ES6语法和常用的web前端框架,如Vue、Angular等
5、有Saas系统或者多商户商城开发经验的优先
6、规范的代码风格、追求较高的代码品味

有意者请跟帖留言。

继续阅读 »

Uniapp移动端混合开发工程师

岗位职责:

  1. 主要负责公司APP产品、小程序、H5相关移动端开发;
  2. 具备前端性能优化经验;
  3. 根据需求认真完成相关功能的界面搭建和业务编码任务;
  4. 良好的沟通与表达能力,思路清晰,有强烈的责任心。

任职要求:
1、计算机相关专业大专及以上学历,1年以上开发经验;
2、熟练使用hbuilderx、uni-app,有参与使用uni-app开发移动端或小程序经验者优先。
3、精通JavaScript、HTML5、和CSS3编程语言,熟悉常见的UI(如:ElementUI、Ant Design Vue等)
4、熟悉ES5和ES6语法和常用的web前端框架,如Vue、Angular等
5、有Saas系统或者多商户商城开发经验的优先
6、规范的代码风格、追求较高的代码品味

有意者请跟帖留言。

收起阅读 »

开通uniCloud(阿里云版)云服务空间和开通前端网页托管

unicloud入门教程

1 开通uniCloud

开通uniCloud的地址为:https://unicloud.dcloud.net.cn/;

注意: 按照国家法律要求和阿里云的要求,使用uniCloud服务,需要先实名认证

3.2. 新建阿里云服务空间

3.3 开通前端网页托管

注意:前端网页托管服务初始化,需要 1-3 分钟,请耐心等待

继续阅读 »

1 开通uniCloud

开通uniCloud的地址为:https://unicloud.dcloud.net.cn/;

注意: 按照国家法律要求和阿里云的要求,使用uniCloud服务,需要先实名认证

3.2. 新建阿里云服务空间

3.3 开通前端网页托管

注意:前端网页托管服务初始化,需要 1-3 分钟,请耐心等待

收起阅读 »

uniapp-图片转base64(支付宝小程序内可用)

最近遇到了一个新需求,使用uniapp开发并打包成小程序在uniapp上运行,页面内涉及到一个图片上传的功能,原先微信小程序内的图片上传对接挺简单的,类似的尝试了一下走文档,发现后端解析图片部分存在问题,经过一番讨论,后端决定让前端将图片信息转成base64再传给接口。
此时问题来了,uniapp内的图片信息转换插件均不支持在支付宝小程序内调用,如不信,可以亲身尝试一波,会提示无权限调用接口。
亲测无效的一个插件

image-tools  

//官方下载后,支付宝小程序真机上测试,直接报错,报错信息为无权限调用该接口

话不多说,直接上可用的实现代码。

页面标签部分:

<view>  
        <canvas id="myCanvas" class="canvas-view" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas>  
</view>

逻辑部分:

export default {  
    data() {  
        return {  
            canvasWidth: 200, //绘制canvas的默认宽度  
            canvasHeight: 200, //绘制canvas的默认高度  
            base64: ''  
        };  
    },  
    methods: {  
        //选择上传图片  
        chooseUploadImg() {  
            const ctx = uni.createCanvasContext('myCanvas');  
            const that = this;  
            uni.chooseImage({  
                count: 1,  
                success: res => {  
                    uni.getImageInfo({  
                        src: res.tempFilePaths[0],  
                        success: function(image) {  
                          //需要动态更新canvas标签的高宽度  
                            that.canvasWidth = image.width;  
                            that.canvasHeight = image.height;  
                            ctx.drawImage(res.tempFilePaths[0], 0, 0, image.width, image.height);  
                            ctx.draw(false, () => {  
                                ctx.toDataURL({}).then(dataURL => {  
                                    const base64Str = dataURL.replace('data:image/png;base64,', '');  
                                    // doSomething  
                                });  
                            });  
                        }  
                    });  
                },  
                fail: e => {  
                    console.log('choose img fail');  
                }  
            });  
        }  
    }  
};  
</script>

样式部分:

canvas-view {  
    position: absolute;  
    top: -2000px;  
    opacity: 0;  
}

大致实现思路为,

  1. 选择图片
  2. 获取图片信息
  3. canvas绘制图片~~~~
  4. canvas原生方法获取base64
  5. 其他处理

本人原文地址:https://segmentfault.com/a/1190000039793934

请多多指教。

继续阅读 »

最近遇到了一个新需求,使用uniapp开发并打包成小程序在uniapp上运行,页面内涉及到一个图片上传的功能,原先微信小程序内的图片上传对接挺简单的,类似的尝试了一下走文档,发现后端解析图片部分存在问题,经过一番讨论,后端决定让前端将图片信息转成base64再传给接口。
此时问题来了,uniapp内的图片信息转换插件均不支持在支付宝小程序内调用,如不信,可以亲身尝试一波,会提示无权限调用接口。
亲测无效的一个插件

image-tools  

//官方下载后,支付宝小程序真机上测试,直接报错,报错信息为无权限调用该接口

话不多说,直接上可用的实现代码。

页面标签部分:

<view>  
        <canvas id="myCanvas" class="canvas-view" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas>  
</view>

逻辑部分:

export default {  
    data() {  
        return {  
            canvasWidth: 200, //绘制canvas的默认宽度  
            canvasHeight: 200, //绘制canvas的默认高度  
            base64: ''  
        };  
    },  
    methods: {  
        //选择上传图片  
        chooseUploadImg() {  
            const ctx = uni.createCanvasContext('myCanvas');  
            const that = this;  
            uni.chooseImage({  
                count: 1,  
                success: res => {  
                    uni.getImageInfo({  
                        src: res.tempFilePaths[0],  
                        success: function(image) {  
                          //需要动态更新canvas标签的高宽度  
                            that.canvasWidth = image.width;  
                            that.canvasHeight = image.height;  
                            ctx.drawImage(res.tempFilePaths[0], 0, 0, image.width, image.height);  
                            ctx.draw(false, () => {  
                                ctx.toDataURL({}).then(dataURL => {  
                                    const base64Str = dataURL.replace('data:image/png;base64,', '');  
                                    // doSomething  
                                });  
                            });  
                        }  
                    });  
                },  
                fail: e => {  
                    console.log('choose img fail');  
                }  
            });  
        }  
    }  
};  
</script>

样式部分:

canvas-view {  
    position: absolute;  
    top: -2000px;  
    opacity: 0;  
}

大致实现思路为,

  1. 选择图片
  2. 获取图片信息
  3. canvas绘制图片~~~~
  4. canvas原生方法获取base64
  5. 其他处理

本人原文地址:https://segmentfault.com/a/1190000039793934

请多多指教。

收起阅读 »