微信主域API简单封装 附带 async await

CocosCreator 不支持 js async await ,需要去 Github 上下载 runtime 环境,将其中 runtime.js 放置到最外层 require 一下就好了。

rutime 获取地址 https://github.com/facebook/regenerator

Klass 语法糖 来自《JavaScript 模式》P132。没有使用CocosCreator自带的cc.Class 便于迁移。

直接上代码。
Klass.js

var Klass = function (Parent_,props_){
    var _ChildKlass,_F,_idx;
    _ChildKlass=function () {
        if(_ChildKlass.prototype.hasOwnProperty("__construct")){
            _ChildKlass.prototype.__construct.apply(this,arguments);
        }
    };
    Parent_=Parent_||Object;
    _F=function(){};
    _F.prototype=Parent_.prototype;
    _ChildKlass.prototype = new _F();
    _ChildKlass.uber = Parent_.prototype;
    _ChildKlass.prototype.construct = _ChildKlass;
    for(_idx in props_){
        if(props_.hasOwnProperty(_idx)){
            _ChildKlass.prototype[_idx]=props_[_idx];
        }
    }
    return _ChildKlass
}
module.exports = Klass;

Base.js

var isString = function(maybeStr_){
    if(typeof(maybeStr_) == "string"){
        return true;
    }else{
        if(Object.prototype.toString.call(maybeStr_) == "[object String]"){
            return true;
        }
    }
    return false;
};
var Klass = require("Klass");
var Base =Klass(null,{__construct:function(className_){this.ctor(className_)},
    ctor : function(className_){
        if (!className_){
            console.error("ERROR Base 没有类名");
        }
        if(!isString(className_)){
            console.error("ERROR Base 类名不是字符串");
        }
        this.className  = className_;
    },
    destory:function(){
    },
})

module.exports = Base;

KeyValueStack.js

var Klass = require("Klass");
var KeyValueStack =Klass(require("Base"),{__construct:function(...args){this.ctor(...args);},
	stack:[],
	ctor : function(){
        KeyValueStack.uber.ctor.call(this,"KeyValueStack");
	},
	pushStack:function(key_, value_) {
		this.stack.push({key:key_,value:value_})
	},
	pullStack:function(){
		if (this.stack.length > 0){
			return this.stack.shift();
		}
		return null;
	},
});
 
module.exports = KeyValueStack;

EventDispatcher.js

var Klass = require("Klass");
var EventDispatcher = Klass(require("Base"),{__construct:function(...args){this.ctor(...args);},
	listeners : [],
	ctor : function(){
        EventDispatcher.uber.ctor.call(this,"EventDispatcher");
	},
    on : function (key_, callback_, target_) {
		if(!(key_ in this.listeners)) {
			this.listeners[key_] = [];
		}
		this.listeners[key_].push({callback:callback_,target:target_});
	},
	off : function(key_, callback_, target_) {
		if(!(key_ in this.listeners)){
            return;
        }
		let _stack = this.listeners[key_];
		for(let _idx = 0, _len = _stack.length; _idx < _len; _idx++) {
            let _element = _stack[_idx];
			if( _element.callback === callback_ && ((_element.target === target_)||(null == target_ && _element.target == target_))){
				_stack.splice(_idx, 1);
                _idx--;
                _len--;
			}
		}
	},
	dispatch : function (key_, value_) {
		if(!(key_ in this.listeners)) {
			return;
		}
		let _stack = this.listeners[key_];
		for(let _idx = 0, _len = _stack.length; _idx < _len; _idx++) {
            let _element = _stack[_idx];
			_element.callback.call(_element.target, value_);
		}
	},
});
 
module.exports = EventDispatcher;

WxUtils.js

/*
    非同步
    {
        funcName:"调用方法名",
        isSuccess:true,//是否成功
        successData:{},//成功时的数据
        failData:{},//失败时的数据
        retryTimes:0,//重试次数
    }
    同步
    {
        funcName:"调用方法名",
        data:{},//API获取到的数据
        ...//其他参数
    }
    //微信Api的结果作为消息分发。把一个SDK当做一个服务器来处理。
    WxUtils.on("login",this.onLogin,this);
    function onLogin(data_){
        console.log(data_.funcName == "login");//true
        if(data_.isSuccess){
            let _wxCode = data_.successData.code;
            //其他操作。
        }
    }
    //提供需要授权的连续操作的建议API
    //如登陆,网路图片保存到相册
*/
require("runtime");
var Klass = require("Klass");
var KeyValueStack = require("KeyValueStack");
var EventDispatcher = require("EventDispatcher");
var WxUtils =Klass(require("Base"),{__construct:function(...args){this.ctor(...args);},
    keyValueStack : new KeyValueStack(),//键值对堆
    eventDispatcher : new EventDispatcher(),//事件分发器
    lastHideTime : 0,//上一次onHide的时间
    transparentButtonDict : {},//透明按钮缓存
    ctor : function(){
        WxUtils.uber.ctor.call(this,"WxUtils");
	},
    on : function(key_, callback_, target_) { //添加监听
        this.eventDispatcher.on(key_, callback_, target_);
    },
    off : function(key_, callback_, target_) { //移除监听
        this.eventDispatcher.off(key_, callback_, target_);
    },
	dispatchAll : function(){ //分发所有事件
        let _keyValueDict = this.keyValueStack.pullStack();
		while(_keyValueDict){
			this.eventDispatcher.dispatch(_keyValueDict.key,_keyValueDict.value);
            _keyValueDict = this.keyValueStack.pullStack();
		}
	},
    update : function(){//帧更新
        this.dispatchAll();
    },
    //创建透明按钮挡在给定的按钮节点上方,这个按钮节点是居中对齐的容器中的第一层级元素。
    // btnType_
    //  createUserInfoButton 创建用户信息 ,这个时,会多两个参数 withCredentials_,lang_
    //    https://developers.weixin.qq.com/minigame/dev/api/open-api/user-info/wx.createUserInfoButton.html
    //  createFeedbackButton 创建反馈信息
    //    https://developers.weixin.qq.com/minigame/dev/api/open-api/feedback/wx.createFeedbackButton.html
    createBtn:function (btnNode_, btnType_, key_, clickFunc_,withCredentials_,lang_) {
        if (btnType_ != "createUserInfoButton" && btnType_ != "createFeedbackButton"){
            console.log("按钮必须是 createUserInfoButton 或 createFeedbackButton 中的一个");
            return;
        }
        var _authBtn = this.transparentButtonDict[key_];//根据 key_ 缓存,下次使用不需要再次创建。
        if(_authBtn){
            _authBtn.show();
        }else{
            var btnSize = cc.size(btnNode_.width + 10, btnNode_.height + 10);
            var frameSize = cc.view.getFrameSize();
            var winSize = cc.director.getWinSize();
            var left = (winSize.width * 0.5 + btnNode_.x - btnSize.width * 0.5) / winSize.width * frameSize.width;
            var top = (winSize.height * 0.5 - btnNode_.y - btnSize.height * 0.5) / winSize.height * frameSize.height;
            var width = btnSize.width / winSize.width * frameSize.width;
            var height = btnSize.height / winSize.height * frameSize.height;
            var btnInfo = { type: 'text', text: '',
                style: {//全部必填项
                    left: left,top: top,width: width,height: height,lineHeight: 0,
                    backgroundColor: '',color: '#ffffff',textAlign: 'center',
                    fontSize: 1,borderRadius: 1
                }
            };
            if (btnType_ == "createUserInfoButton"){
                if (withCredentials_){
                    btnInfo.withCredentials = true;
                }
                if (lang_){
                    btnInfo.lang = lang_;
                }
            }
            _authBtn = wx[btnType_](btnInfo);
            this.transparentButtonDict[key_] = _authBtn;
        }
        _authBtn.onTap((res_) => {
            clickFunc_(res_); //res_ 在 createUserInfoButton 的情况下,是用户信息。
            _authBtn.hide();
        });
        return _authBtn;//_authBtn.hide(); 隐藏的实际交给具体代码。有可能不点击按钮,也要隐藏。
    },
    
    //创建一个按钮,等待点击
    createBtnPromise:function(btnNode_, btnType_, key_, withCredentials_, lang_){
        return new Promise((resolve_)=> {
            this.createBtn(btnNode_, btnType_, key_, (res_)=>{
                resolve_(res_);//返回信息
            },withCredentials_,lang_);
        });
    },
 
    onNetworkStatusChange : function(){
        wx.onNetworkStatusChange((data_)=>{
            this.keyValueStack.pushStack("onNetworkStatusChange",{
                funcName:"onNetworkStatusChange",
                data:data_
            });
        });
    },
    showToast : function(title_,lastTime_){
        wx.showToast({title: title_,duration: lastTime_});
    },
    onShow : function(){
        wx.onShow((data_)=>{
            let _showTime = Date.parse(new Date())/1000;
            this.keyValueStack.pushStack("onShow",{
                funcName:"onShow",
                diffTimeInSecond:_showTime - this.lastHideTime,
                data:data_
            });
            this.lastHideTime = 0;
        });
    },
    onHide : function(){
        wx.onHide((data_)=>{
		    this.lastHideTime = Date.parse(new Date())/1000;
            this.keyValueStack.pushStack("onHide",{
                funcName:"onHide",
                data:data_
            });
        });
    },
    //https://developers.weixin.qq.com/minigame/dev/api/base/app/life-cycle/wx.getLaunchOptionsSync.html
    getLaunchOptionsSync : function(){//登陆参数同步
        let _data = wx.getLaunchOptionsSync();
        this.keyValueStack.pushStack("getLaunchOptionsSync",{funcName:"getLaunchOptionsSync",isSuccess:true,successData:_data});
        return _data;
    },
    //同步方法
    //getNetworkType -> https://developers.weixin.qq.com/minigame/dev/api/device/network/wx.getNetworkType.html
    //getSetting -> https://developers.weixin.qq.com/minigame/dev/api/open-api/setting/wx.getSetting.html
    //getSystemInfo -> https://developers.weixin.qq.com/minigame/dev/api/base/system/system-info/wx.getSystemInfo.html
    //getUserInfo -> https://developers.weixin.qq.com/minigame/dev/api/open-api/user-info/wx.getUserInfo.html
    //getClipboardData -> https://developers.weixin.qq.com/minigame/dev/api/device/clipboard/wx.getClipboardData.html
    //authorize -> https://developers.weixin.qq.com/minigame/dev/api/open-api/authorize/wx.authorize.html
    //request -> https://developers.weixin.qq.com/minigame/dev/api/network/request/wx.request.html
    //downloadFile -> https://developers.weixin.qq.com/minigame/dev/api/network/download/wx.downloadFile.html
    //saveImageToPhotosAlbum -> https://developers.weixin.qq.com/minigame/dev/api/media/image/wx.saveImageToPhotosAlbum.html
    //login -> https://developers.weixin.qq.com/minigame/dev/api/open-api/login/wx.login.html
    getFuncAwait : function(funcName_,requestData_ = {} , needLoadingStr_ = null , retryTimes_ = 0){
        return new Promise((resolve_)=> {
            this.getFunc(funcName_,requestData_,needLoadingStr_,retryTimes_,resolve_);
        });
    },
    //非同步get类封装,
    getFunc : function(funcName_,requestData_ = {} , needLoadingStr_ = null , retryTimes_ = 0,resolve_ = null){
        let _isSuccess = false;//是否成功执行
        let _successData = null;
        let _failData = null;
        if (needLoadingStr_){
            wx.showLoading({title: needLoadingStr_,mask: true});
        }
        let _success = (args_)=>{
            console.log("WxMain : " + funcName_ + " success : ",args_);
            _isSuccess = true;
            _successData = args_;
        };
        let _fail = (args_)=>{
            console.log("WxMain : " + funcName_ + " fail : ",args_);
            _isSuccess = false;
            _failData = args_;
        };
        let _complete = (args_)=>{
            console.log("WxMain : " + funcName_ + " complete : ",args_);
            if (retryTimes_ > 0 && !_isSuccess){
                retryTimes_--;
                wx[funcName_](requestData_);//第N次访问微信
            }else{
                let _value = {funcName:funcName_,retryTimes:retryTimes_,isSuccess:_isSuccess,successData:_successData,failData:_failData};
                this.keyValueStack.pushStack(_value.funcName,_value);
                if (needLoadingStr_){
                    wx.hideLoading();
                }
                if (resolve_){// 作为 await 内调用的方法,有这个参数。
                    resolve_(_value);
                }
            }
        };
        requestData_.success = _success;
        requestData_.fail = _fail;
        requestData_.complete = _complete;
        wx[funcName_](requestData_);//第一次访问微信
    },
    /*
        subscribeInfoList_ 元素格式
        [
            {
                key:"Key",//字符串键,用来简易标示提示项
                id:"SPCJOSAMGSMVKSNHWTUJTEOMSCOAPOFSAGJAOEWJMGK",//后台填写的id
                title:"提示授权标题",//提示授权时的文字
                triggered:false,//是否提示过授权
            },
            ...
        ]
    */
    initSubscribeMessage:function(subscribeInfoList_){
        this.subscribeInfoList = subscribeInfoList_;
    },
    /*
        WxUtils.subscribeMessage(["Key","Key1","Key2"]).then((acceptKeyList_)=>{
            console.log(acceptKeyList_);
        });
    */
    subscribeMessage:async function(keyOrKeyList_) {
        if(!this.subscribeInfoList){
            console.error("订阅相关的授权,先要调用 initSubscribeMessage 设置项目");
        }
        //通过key的指定获取实际的id
        let _idList = [];
        if(keyOrKeyList_ == "ALL" || keyOrKeyList_[0] == "ALL"){ // 键为全部的时候,所有的都提示
            this.subscribeInfoList.forEach((subscribeInfo_)=>{
                if(subscribeInfo_.triggered == false){
                    _idList.push(subscribeInfo_.id);
                    subscribeInfo_.triggered = true;
                }
            });
        }else{//给定几个或者一个的时候,只提示给定的
            let _keyList = null;
            if(Array.isArray(keyOrKeyList_)){
                _keyList = keyOrKeyList_;
            }else{
                _keyList = [keyOrKeyList_];
            }
            _keyList.forEach((key_)=>{
                this.subscribeInfoList.some((subscribeInfo_)=>{
                    if(subscribeInfo_.triggered == false && key_ == subscribeInfo_.key){
                        _idList.push(subscribeInfo_.id);
                        subscribeInfo_.triggered = true;
                        return true;//some 返回 true 打断 some 的循环
                    }
                });
            });
        }
        if (_idList.length > 0){//需要提示的id列表。大于零,证明有需要提示的
            let _retryTimes = 3;
            let _result = null;
            _result = await this.getFuncAwait("requestSubscribeMessage",{tmplIds: _idList},"用户授权订阅",0);//用户操作,0次重试
            if(!_result.isSuccess){
                this.showToast("取消订阅授权",1000);
                return null;
            }
            let _acceptKeyList = [];
            _idList.forEach((id_)=>{
                if (isSuccess.successData[id_] == 'accept') {
                    this.subscribeInfoList.some((subscribeInfo_)=>{
                        if(subscribeInfo_.id == id_){
                            _acceptKeyList.push(subscribeInfo_.key);
                            return true;//some 返回 true 打断 some 的循环
                        }
                    });
                }
            });
            if(_acceptKeyList.length > 0){//有同意的,将同意的列表传递回去
                return _acceptKeyList;
            }else{//一个都没同意
                return null;
            }
        }else{//给定的键,当前运行时都提示用户授权了
            return null;
        } 
    },
    /*
        WxUtils.loginAndGetUserInfo().then((loginAndUser_)=>{
            console.log(loginAndUser_);
        });
    */
    loginAndGetUserInfo:async function(userInfoBtnNode_,withCredentials_,lang_){
        if(userInfoBtnNode_.active){
            console.warn("用户授权按钮的显示由后续判断决定,这里会强制设置成false");
            userInfoBtnNode_.active = false;
        }
        let _retryTimes = 3;
        let _result = null;
 
        _result = await this.getFuncAwait("login",{},"用户登录",_retryTimes);
        if(!_result.isSuccess){
            this.showToast("用户登录失败",1000);
            return null;
        }
        let _loginData = _result.successData;
 
        _result = await this.getFuncAwait("getSetting",{},"获取授权信息",_retryTimes);
        if(!_result.isSuccess){
            this.showToast("获取授权信息失败",1000);
            return null;
        }
        
        let _userData = null;
        if(!_result.successData.authSetting['scope.userInfo']){//并未授权用户信息
            userInfoBtnNode_.active = true;
            _userData = await this.createBtnPromise(userInfoBtnNode_,"createUserInfoButton","GETUSERINFO",null,withCredentials_,lang_);//点击授权按钮
            userInfoBtnNode_.active = false;
            if (_userData.encryptedData && _userData.iv) {
                this.showToast("授权成功",1000);
            } else {
                this.showToast("未授权",1000);
                return null;
            }
        }else{
            _result = await this.getFuncAwait("getUserInfo",{withCredentials: withCredentials_,lang:lang_},"获取用户信息",_retryTimes);
            if(!_result.isSuccess){
                this.showToast("获取用户信息失败",1000);
                return null;
            }
            _userData = _result.successData;
        }
        if(_userData){//返回的是 登陆成功返回数据 和 用户信息。
            return { login:_loginData, user:_userData};
        }else{
            this.showToast("登陆授权失败",1000);
            return null;
        }
    },
    //保存图片到相册
    /*
        WxUtils.downloadImageToPhotosAlbum("https://xxxxx.png").then((successBool_)=>{
            console.log(successBool_);
        });
    */
    downloadImageToPhotosAlbum : async function(imageUrl_){
        let _retryTimes = 3;
        let _result = null;
        _result = await this.getFuncAwait("getSetting",{},"获取授权信息",_retryTimes);
        if(!_result.isSuccess){
            this.showToast("获取授权信息失败",1000);
            return false;
        }
        if(!_result.successData.authSetting['scope.writePhotosAlbum']){//未授权过
            _result = await this.getFuncAwait("authorize",{scope: 'scope.writePhotosAlbum'},"授权相册",_retryTimes);
            if(!_result.isSuccess){
                this.showToast("授权相册失败",1000);
                return false;
            }
        }
        _result = await this.getFuncAwait("downloadFile",{
            url:imageUrl_,
            filePath: wx.env.USER_DATA_PATH + '/' + new Date().valueOf() + ".png",
        },"下载图片中",_retryTimes);
        if(!_result.isSuccess){
            this.showToast("图片下载失败",1000);
            return false;
        }
        let _tempFilePath = _result.successData.filePath;
        _result = await this.getFuncAwait("saveImageToPhotosAlbum",{filePath:_tempFilePath},"保存图片中",_retryTimes);
        if(!_result.isSuccess){
            this.showToast("保存图片失败",1000);
            return false;
        }
        return true;
    },
});
module.exports = WxUtils;

没经过测试,相信你我都是复制粘贴胡编乱造的高手