react-native-wxwork
Version:
react-native library for wxwork app
395 lines (359 loc) • 11.5 kB
JavaScript
;
import {
DeviceEventEmitter,
NativeModules,
Platform,
NativeEventEmitter
} from "react-native";
import { EventEmitter } from "events";
let isAppRegistered = false;
const { RNWxwork } = NativeModules;
// Event emitter to dispatch request and response from RNWxwork.
const emitter = new EventEmitter();
const WXWorkEmitter = new NativeEventEmitter(RNWxwork);
DeviceEventEmitter.addListener("WeChat_Resp", resp => {
emitter.emit(resp.type, resp);
});
function wrapRegisterApp(nativeFunc) {
if (!nativeFunc) {
return undefined;
}
return (...args) => {
if (isAppRegistered) {
// FIXME(Yorkie): we ignore this error if AppRegistered is true.
return Promise.resolve(true);
}
isAppRegistered = true;
return new Promise((resolve, reject) => {
nativeFunc.apply(null, [
...args,
(error, result) => {
if (!error) {
return resolve(result);
}
if (typeof error === "string") {
return reject(new Error(error));
}
reject(error);
}
]);
});
};
}
function wrapApi(nativeFunc) {
if (!nativeFunc) {
return undefined;
}
return (...args) => {
if (!isAppRegistered) {
return Promise.reject(new Error("registerApp required."));
}
return new Promise((resolve, reject) => {
nativeFunc.apply(null, [
...args,
(error, result) => {
if (!error) {
return resolve(result);
}
if (typeof error === "string") {
return reject(new Error(error));
}
reject(error);
}
]);
});
};
}
/**
* `addListener` inherits from `events` module
* @method addListener
* @param {String} eventName - the event name
* @param {Function} trigger - the function when event is fired
*/
export const addListener = emitter.addListener.bind(emitter);
/**
* `once` inherits from `events` module
* @method once
* @param {String} eventName - the event name
* @param {Function} trigger - the function when event is fired
*/
export const once = emitter.once.bind(emitter);
/**
* `removeAllListeners` inherits from `events` module
* @method removeAllListeners
* @param {String} eventName - the event name
*/
export const removeAllListeners = emitter.removeAllListeners.bind(emitter);
/**
* @method registerApp
* @param {String} appid - the app id
* @return {Promise}
*/
export const registerApp = wrapRegisterApp(RNWxwork.registerApp);
/**
* @method registerWWApp
* @param {String} schema - schema
* @return {Promise}
*/
export const registerWWApp = wrapRegisterApp(RNWxwork.registerWWApp);
/**
* @method registerAppWithDescription
* @param {String} appid - the app id
* @param {String} appdesc - the app description
* @return {Promise}
*/
export const registerAppWithDescription = wrapRegisterApp(
RNWxwork.registerAppWithDescription
);
/**
* Return if the wechat app is installed in the device.
* @method isWXAppInstalled
* @return {Promise}
*/
export const isWXAppInstalled = wrapApi(RNWxwork.isWXAppInstalled);
/**
* Return if the wechat app is installed in the device.
* @method isWXAppInstalled
* @return {Promise}
*/
export const isWWAppInstalled = wrapApi(RNWxwork.isWWAppInstalled);
/**
* Return if the wechat application supports the api
* @method isWXAppSupportApi
* @return {Promise}
*/
export const isWXAppSupportApi = wrapApi(RNWxwork.isWXAppSupportApi);
/**
* Return if the wechat application supports the api
* @method isWWAppSupportApi
* @return {Promise}
*/
export const isWWAppSupportApi = wrapApi(RNWxwork.isWWAppSupportApi);
/**
* Get the wechat app installed url
* @method getWWAppInstallUrl
* @return {String} the wechat app installed url
*/
export const getWWAppInstallUrl = wrapApi(RNWxwork.getWWAppInstallUrl);
/**
* Get the wechat app installed url
* @method getWXAppInstallUrl
* @return {String} the wechat app installed url
*/
export const getWXAppInstallUrl = wrapApi(RNWxwork.getWXAppInstallUrl);
/**
* Get the wechat api version
* @method getApiVersion
* @return {String} the api version string
*/
export const getApiVersion = wrapApi(RNWxwork.getApiVersion);
/**
* Get the wxwork api version
* @method getWWApiVersion
* @return {String} the api version string
*/
export const getWWApiVersion = wrapApi(RNWxwork.getWWApiVersion);
/**
* Open wechat app
* @method openWXApp
* @return {Promise}
*/
export const openWXApp = wrapApi(RNWxwork.openWXApp);
/**
* Open wxwork app
* @method openWWApp
* @return {Promise}
*/
export const openWWApp = wrapApi(RNWxwork.openWWApp);
// wrap the APIs
const nativeShareToTimeline = wrapApi(RNWxwork.shareToTimeline);
const nativeShareToSession = wrapApi(RNWxwork.shareToSession);
const nativeShareToFavorite = wrapApi(RNWxwork.shareToFavorite);
const nativeSendAuthRequest = wrapApi(RNWxwork.sendAuthRequest);
/**
* @method sendAuthRequest
* @param {Array} scopes - the scopes for authentication.
* @return {Promise}
*/
export function sendAuthRequest(scopes, state) {
return new Promise((resolve, reject) => {
RNWxwork.sendAuthRequest(scopes, state, () => {});
emitter.once("SendAuth.Resp", resp => {
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* @method sendWWAuthRequest
* @param {Array} schema - the scopes for authentication.
* @return {Promise}
*/
export function sendWWAuthRequest(schema, appid, agentid) {
return new Promise((resolve, reject) => {
RNWxwork.sendWWAuthRequest(schema, appid, agentid, () => {});
emitter.once("SendAuth.Resp", resp => {
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* @method sendWWAuthRequest
* @param {Array} schema - the scopes for authentication.
* @return {Promise}
*/
export function sendSSORequest() {
return new Promise((resolve, reject) => {
RNWxwork.sendSSORequest(() => {});
emitter.once("SendAuth.Resp", resp => {
console.log(resp);
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* Share something to timeline/moments/朋友圈
* @method shareToTimeline
* @param {Object} data
* @param {String} data.thumbImage - Thumb image of the message, which can be a uri or a resource id.
* @param {String} data.type - Type of this message. Could be {news|text|imageUrl|imageFile|imageResource|video|audio|file}
* @param {String} data.webpageUrl - Required if type equals news. The webpage link to share.
* @param {String} data.imageUrl - Provide a remote image if type equals image.
* @param {String} data.videoUrl - Provide a remote video if type equals video.
* @param {String} data.musicUrl - Provide a remote music if type equals audio.
* @param {String} data.filePath - Provide a local file if type equals file.
* @param {String} data.fileExtension - Provide the file type if type equals file.
*/
export function shareToTimeline(data) {
return new Promise((resolve, reject) => {
nativeShareToTimeline(data);
emitter.once("SendMessageToWX.Resp", resp => {
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* Share something to a friend or group
* @method shareToSession
* @param {Object} data
* @param {String} data.thumbImage - Thumb image of the message, which can be a uri or a resource id.
* @param {String} data.type - Type of this message. Could be {news|text|imageUrl|imageFile|imageResource|video|audio|file}
* @param {String} data.webpageUrl - Required if type equals news. The webpage link to share.
* @param {String} data.imageUrl - Provide a remote image if type equals image.
* @param {String} data.videoUrl - Provide a remote video if type equals video.
* @param {String} data.musicUrl - Provide a remote music if type equals audio.
* @param {String} data.filePath - Provide a local file if type equals file.
* @param {String} data.fileExtension - Provide the file type if type equals file.
*/
export function shareToSession(data) {
return new Promise((resolve, reject) => {
nativeShareToSession(data);
emitter.once("SendMessageToWX.Resp", resp => {
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* Share something to favorite
* @method shareToFavorite
* @param {Object} data
* @param {String} data.thumbImage - Thumb image of the message, which can be a uri or a resource id.
* @param {String} data.type - Type of this message. Could be {news|text|imageUrl|imageFile|imageResource|video|audio|file}
* @param {String} data.webpageUrl - Required if type equals news. The webpage link to share.
* @param {String} data.imageUrl - Provide a remote image if type equals image.
* @param {String} data.videoUrl - Provide a remote video if type equals video.
* @param {String} data.musicUrl - Provide a remote music if type equals audio.
* @param {String} data.filePath - Provide a local file if type equals file.
* @param {String} data.fileExtension - Provide the file type if type equals file.
*/
export function shareToFavorite(data) {
return new Promise((resolve, reject) => {
nativeShareToFavorite(data);
emitter.once("SendMessageToWX.Resp", resp => {
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* wechat pay
* @param {Object} data
* @param {String} data.partnerId
* @param {String} data.prepayId
* @param {String} data.nonceStr
* @param {String} data.timeStamp
* @param {String} data.package
* @param {String} data.sign
* @returns {Promise}
*/
export function pay(data) {
// FIXME(Yorkie): see https://github.com/yorkie/react-native-wechat/issues/203
// Here the server-side returns params in lowercase, but here SDK requires timeStamp
// for compatibility, we make this correction for users.
function correct(actual, fixed) {
if (!data[fixed] && data[actual]) {
data[fixed] = data[actual];
delete data[actual];
}
}
correct("prepayid", "prepayId");
correct("noncestr", "nonceStr");
correct("partnerid", "partnerId");
correct("timestamp", "timeStamp");
// FIXME(94cstyles)
// Android requires the type of the timeStamp field to be a string
if (Platform.OS === "android") data.timeStamp = String(data.timeStamp);
return new Promise((resolve, reject) => {
RNWxwork.pay(data, result => {
if (result) reject(result);
});
emitter.once("PayReq.Resp", resp => {
if (resp.errCode === 0) {
resolve(resp);
} else {
reject(new WechatError(resp));
}
});
});
}
/**
* promises will reject with this error when API call finish with an errCode other than zero.
*/
export class WechatError extends Error {
constructor(resp) {
const message = resp.errStr || resp.errCode.toString();
super(message);
this.name = "WechatError";
this.code = resp.errCode;
// avoid babel's limition about extending Error class
// https://github.com/babel/babel/issues/3083
if (typeof Object.setPrototypeOf === "function") {
Object.setPrototypeOf(this, WechatError.prototype);
} else {
this.__proto__ = WechatError.prototype;
}
}
}
export default RNWxwork;