@norcy/react-native-toolkit 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/ConfigDataModel.js +122 -0
- package/lib/commonjs/ConfigDataModel.js.map +1 -0
- package/lib/commonjs/DevConfig.js +9 -5
- package/lib/commonjs/DevConfig.js.map +1 -1
- package/lib/commonjs/Frequence.js +67 -0
- package/lib/commonjs/Frequence.js.map +1 -0
- package/lib/commonjs/LoginManager.js +21 -18
- package/lib/commonjs/LoginManager.js.map +1 -1
- package/lib/commonjs/MessageModel.js +157 -0
- package/lib/commonjs/MessageModel.js.map +1 -0
- package/lib/commonjs/PrefData.js +10 -0
- package/lib/commonjs/PrefData.js.map +1 -1
- package/lib/commonjs/SentryManager.js +3 -3
- package/lib/commonjs/SentryManager.js.map +1 -1
- package/lib/commonjs/Tool.js +52 -0
- package/lib/commonjs/Tool.js.map +1 -0
- package/lib/commonjs/VipAndroidManager.js +154 -0
- package/lib/commonjs/VipAndroidManager.js.map +1 -0
- package/lib/commonjs/VipManager.js +280 -0
- package/lib/commonjs/VipManager.js.map +1 -0
- package/lib/commonjs/index.js +72 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/ConfigDataModel.js +117 -0
- package/lib/module/ConfigDataModel.js.map +1 -0
- package/lib/module/DevConfig.js +5 -1
- package/lib/module/DevConfig.js.map +1 -1
- package/lib/module/Frequence.js +61 -0
- package/lib/module/Frequence.js.map +1 -0
- package/lib/module/LoginManager.js +5 -2
- package/lib/module/LoginManager.js.map +1 -1
- package/lib/module/MessageModel.js +151 -0
- package/lib/module/MessageModel.js.map +1 -0
- package/lib/module/PrefData.js +10 -0
- package/lib/module/PrefData.js.map +1 -1
- package/lib/module/SentryManager.js +1 -1
- package/lib/module/SentryManager.js.map +1 -1
- package/lib/module/Tool.js +46 -0
- package/lib/module/Tool.js.map +1 -0
- package/lib/module/VipAndroidManager.js +145 -0
- package/lib/module/VipAndroidManager.js.map +1 -0
- package/lib/module/VipManager.js +273 -0
- package/lib/module/VipManager.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/ConfigDataModel.d.ts +17 -0
- package/lib/typescript/DevConfig.d.ts +1 -1
- package/lib/typescript/Frequence.d.ts +10 -0
- package/lib/typescript/LoginManager.d.ts +2 -3
- package/lib/typescript/MessageModel.d.ts +26 -0
- package/lib/typescript/Tool.d.ts +7 -0
- package/lib/typescript/VipAndroidManager.d.ts +28 -0
- package/lib/typescript/VipManager.d.ts +29 -0
- package/lib/typescript/index.d.ts +6 -0
- package/package.json +5 -3
- package/src/ConfigDataModel.ts +146 -0
- package/src/DevConfig.ts +4 -1
- package/src/Frequence.ts +70 -0
- package/src/LoginManager.ts +6 -9
- package/src/MessageModel.ts +191 -0
- package/src/PrefData.ts +10 -0
- package/src/SentryManager.ts +2 -1
- package/src/Tool.ts +64 -0
- package/src/VipAndroidManager.ts +110 -0
- package/src/VipManager.ts +282 -0
- package/src/index.tsx +6 -0
- package/ios/ReactNativeToolkit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -4
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import Purchases, { PurchasesPackage } from 'react-native-purchases';
|
|
2
|
+
import * as WeChat from 'react-native-wechat-lib';
|
|
3
|
+
import { ConfigDataModel } from './ConfigDataModel';
|
|
4
|
+
import { LoginManager } from './LoginManager';
|
|
5
|
+
import { Tool } from './Tool';
|
|
6
|
+
|
|
7
|
+
let SERVER_URL = '';
|
|
8
|
+
|
|
9
|
+
export const VipAndroidManager = {
|
|
10
|
+
init: ({ WeChatPayServer }: { WeChatPayServer: string }) => {
|
|
11
|
+
SERVER_URL = WeChatPayServer;
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
queryOrder: async (orderId?: string) => {
|
|
15
|
+
const user = LoginManager.currentUser();
|
|
16
|
+
// Step1:生成预订单
|
|
17
|
+
try {
|
|
18
|
+
const rawResponse = await fetch(SERVER_URL, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Accept': 'application/json',
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
user: user?.AVUser.get('objectId'),
|
|
26
|
+
order: orderId,
|
|
27
|
+
cmd: 'check',
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
const res = await rawResponse.json();
|
|
31
|
+
// console.log(res);
|
|
32
|
+
if (rawResponse.status === 200 && !res.error) {
|
|
33
|
+
return { paid: res.paid };
|
|
34
|
+
} else {
|
|
35
|
+
return { paid: false, e: res.error };
|
|
36
|
+
}
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return { paid: false, e: e };
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
recover: async () => {
|
|
43
|
+
const { paid, e } = await VipAndroidManager.queryOrder();
|
|
44
|
+
if (paid && !e) {
|
|
45
|
+
await Purchases.invalidateCustomerInfoCache();
|
|
46
|
+
console.log('恢复成功');
|
|
47
|
+
return { errorCode: 0 };
|
|
48
|
+
} else {
|
|
49
|
+
if (e) {
|
|
50
|
+
console.log('恢复失败(-3)', JSON.stringify(e));
|
|
51
|
+
return { errorCode: -3, errorMsg: JSON.stringify(e) };
|
|
52
|
+
} else {
|
|
53
|
+
console.log('恢复失败(-2)');
|
|
54
|
+
return { errorCode: -2 };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
getPackages: () => {
|
|
60
|
+
return ConfigDataModel.get('vip_android_products');
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
purchase: async (purchasePackage: PurchasesPackage) => {
|
|
64
|
+
try {
|
|
65
|
+
const user = LoginManager.currentUser();
|
|
66
|
+
// Step1:生成预订单
|
|
67
|
+
const rawResponse = await fetch(SERVER_URL, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: {
|
|
70
|
+
'Accept': 'application/json',
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
user: user?.AVUser.get('objectId'),
|
|
75
|
+
product: purchasePackage.product?.identifier,
|
|
76
|
+
cmd: 'prepare',
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
const res = await rawResponse.json();
|
|
80
|
+
// console.log(res);
|
|
81
|
+
if (rawResponse.status === 200 && !res.error) {
|
|
82
|
+
// Step2:调用微信支付 SDK
|
|
83
|
+
const { errCode, errStr } = await WeChat.pay(res.payload);
|
|
84
|
+
if (errCode) {
|
|
85
|
+
console.log('购买失败(-5)', errStr);
|
|
86
|
+
return { errorCode: -5, errorMsg: errStr };
|
|
87
|
+
}
|
|
88
|
+
// 虽然没什么问题,但保险起见还是延时下,让后台先更新
|
|
89
|
+
await Tool.sleep(4000);
|
|
90
|
+
// Step3:查询后台
|
|
91
|
+
const { paid, e } = await VipAndroidManager.queryOrder(
|
|
92
|
+
res.payload.order
|
|
93
|
+
);
|
|
94
|
+
if (paid && !e) {
|
|
95
|
+
await Purchases.invalidateCustomerInfoCache();
|
|
96
|
+
return { errorCode: 0 };
|
|
97
|
+
} else {
|
|
98
|
+
console.log('购买失败(-5)', JSON.stringify(e));
|
|
99
|
+
return { errorCode: -5, errorMsg: JSON.stringify(e) };
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
console.log('购买失败(-5)', JSON.stringify(res?.error));
|
|
103
|
+
return { errorCode: -5, errorMsg: JSON.stringify(res?.error) };
|
|
104
|
+
}
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.log('购买失败(-5)', JSON.stringify(e));
|
|
107
|
+
return { errorCode: -5, errorMsg: JSON.stringify(e) };
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import Purchases, {
|
|
3
|
+
CustomerInfo,
|
|
4
|
+
PurchasesPackage,
|
|
5
|
+
} from 'react-native-purchases';
|
|
6
|
+
import { DevConfig } from './DevConfig';
|
|
7
|
+
import { LoginManager } from './LoginManager';
|
|
8
|
+
import { Notification } from './Notification';
|
|
9
|
+
import { BuildInPrefs } from './PrefData';
|
|
10
|
+
import { Tool } from './Tool';
|
|
11
|
+
import { VipAndroidManager } from './VipAndroidManager';
|
|
12
|
+
import { UserType } from './constant';
|
|
13
|
+
|
|
14
|
+
let _customerInfo: CustomerInfo | null;
|
|
15
|
+
let _RC_ENTITLEMENT_ID: string = '';
|
|
16
|
+
|
|
17
|
+
export const VipManager = {
|
|
18
|
+
init: ({
|
|
19
|
+
RC_API_KEY,
|
|
20
|
+
RC_ENTITLEMENT_ID,
|
|
21
|
+
WeChatPayServer,
|
|
22
|
+
}: {
|
|
23
|
+
RC_API_KEY: string;
|
|
24
|
+
RC_ENTITLEMENT_ID: string;
|
|
25
|
+
WeChatPayServer: string;
|
|
26
|
+
}) => {
|
|
27
|
+
console.log('Vip 模块初始化');
|
|
28
|
+
|
|
29
|
+
VipAndroidManager.init({ WeChatPayServer });
|
|
30
|
+
|
|
31
|
+
_RC_ENTITLEMENT_ID = RC_ENTITLEMENT_ID;
|
|
32
|
+
|
|
33
|
+
Purchases.configure({
|
|
34
|
+
apiKey: RC_API_KEY,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
VipManager.refreshVip();
|
|
38
|
+
|
|
39
|
+
Notification.addListener(
|
|
40
|
+
'onLogin',
|
|
41
|
+
async ({ error, user }: { error: any; user: UserType }) => {
|
|
42
|
+
console.log('Vip 模块用户登录');
|
|
43
|
+
if (!error && user) {
|
|
44
|
+
try {
|
|
45
|
+
await Purchases.logIn(user.AVUser.get('objectId'));
|
|
46
|
+
await Purchases.setAttributes({ nickname: user.nickname });
|
|
47
|
+
await VipManager.refreshVip();
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error(e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
Notification.addListener('onLogout', () => {
|
|
56
|
+
Purchases.logOut();
|
|
57
|
+
_customerInfo = null;
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
purchase: async (purchasePackage: PurchasesPackage) => {
|
|
62
|
+
if (!LoginManager.isLogin()) {
|
|
63
|
+
return { errorCode: -1 };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!purchasePackage) {
|
|
67
|
+
return { errorCode: -4 };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log('购买商品', purchasePackage);
|
|
71
|
+
|
|
72
|
+
if (Platform.OS === 'android') {
|
|
73
|
+
return await VipAndroidManager.purchase(purchasePackage);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const { customerInfo } = await Purchases.purchasePackage(purchasePackage);
|
|
78
|
+
|
|
79
|
+
await VipManager.refreshVip(customerInfo);
|
|
80
|
+
if (
|
|
81
|
+
typeof customerInfo.entitlements.active[_RC_ENTITLEMENT_ID] !==
|
|
82
|
+
'undefined'
|
|
83
|
+
) {
|
|
84
|
+
console.log('购买成功');
|
|
85
|
+
return { errorCode: 0 };
|
|
86
|
+
} else {
|
|
87
|
+
console.log('购买失败(-5)');
|
|
88
|
+
return { errorCode: -5, errorMsg: '' };
|
|
89
|
+
}
|
|
90
|
+
} catch (e: any) {
|
|
91
|
+
if (!e.userCancelled) {
|
|
92
|
+
console.log('购买失败(-5)', e.message);
|
|
93
|
+
return { errorCode: -5, errorMsg: e.message };
|
|
94
|
+
} else {
|
|
95
|
+
console.log('购买取消(-2)');
|
|
96
|
+
return { errorCode: -2 };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
recover: async () => {
|
|
102
|
+
if (!LoginManager.isLogin()) {
|
|
103
|
+
return { errorCode: -1 };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
if (Platform.OS === 'android') {
|
|
108
|
+
return await VipAndroidManager.recover();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('iOS 恢复购买');
|
|
112
|
+
const customerInfo = await Purchases.restorePurchases();
|
|
113
|
+
await VipManager.refreshVip(customerInfo);
|
|
114
|
+
if (customerInfo.entitlements.active?.vip) {
|
|
115
|
+
console.log('恢复成功');
|
|
116
|
+
return { errorCode: 0 };
|
|
117
|
+
} else {
|
|
118
|
+
console.log('恢复失败(-2)');
|
|
119
|
+
return { errorCode: -2 };
|
|
120
|
+
}
|
|
121
|
+
} catch (e: any) {
|
|
122
|
+
console.log('恢复失败(-3)', e.message);
|
|
123
|
+
return { errorCode: -3, errorMsg: e.message };
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
getPackages: async (): Promise<PurchasesPackage[]> => {
|
|
128
|
+
if (VipManager.isForeverVip()) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (Platform.OS === 'android' || __DEV__) {
|
|
133
|
+
return VipAndroidManager.getPackages();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const offerings = await Purchases.getOfferings();
|
|
138
|
+
let targetOffering = offerings.current;
|
|
139
|
+
if (__DEV__) {
|
|
140
|
+
targetOffering = offerings.all.NormalVip;
|
|
141
|
+
}
|
|
142
|
+
console.log('获取商品');
|
|
143
|
+
if (
|
|
144
|
+
targetOffering !== null &&
|
|
145
|
+
targetOffering.availablePackages.length !== 0
|
|
146
|
+
) {
|
|
147
|
+
let packages = targetOffering.availablePackages;
|
|
148
|
+
// 如果是订阅的,非试用的,展示永久 VIP
|
|
149
|
+
if (VipManager.isVip() && !VipManager.isTrailVip()) {
|
|
150
|
+
packages = packages.filter((item) => {
|
|
151
|
+
return item;
|
|
152
|
+
// TODO
|
|
153
|
+
// return item.product.productCategory === 'NON_SUBSCRIPTION';
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return packages;
|
|
157
|
+
} else {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
} catch (e) {
|
|
161
|
+
console.error('Get Product Fail', e);
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
isVip: () => {
|
|
167
|
+
let _isVip = _customerInfo?.entitlements?.active?.vip?.isActive;
|
|
168
|
+
if (
|
|
169
|
+
_isVip &&
|
|
170
|
+
!__DEV__ &&
|
|
171
|
+
_customerInfo?.entitlements?.active?.vip.isSandbox
|
|
172
|
+
) {
|
|
173
|
+
_isVip = false;
|
|
174
|
+
}
|
|
175
|
+
if (__DEV__) {
|
|
176
|
+
if (DevConfig.hasValue(BuildInPrefs.DevVip)) {
|
|
177
|
+
_isVip = DevConfig.getValue(BuildInPrefs.DevVip);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return _isVip;
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
isForeverVip: () => {
|
|
184
|
+
// 苹果的永久会员是非订阅制的,因此 RevenueCat 的 vipEndTime 会空
|
|
185
|
+
return (
|
|
186
|
+
VipManager.isVip() &&
|
|
187
|
+
(VipManager.vipEndTime()?.length === 0 ||
|
|
188
|
+
VipManager.vipCountDay() >= 36500)
|
|
189
|
+
);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
vipEndTime: () => {
|
|
193
|
+
const time = _customerInfo?.entitlements?.active?.vip?.expirationDate;
|
|
194
|
+
if (VipManager.isVip() && time) {
|
|
195
|
+
const date = new Date(time);
|
|
196
|
+
return Tool.formatDate(date, 'yyyy-MM-dd');
|
|
197
|
+
} else {
|
|
198
|
+
return '';
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
vipCountDay: () => {
|
|
203
|
+
const time = _customerInfo?.entitlements?.active?.vip?.expirationDate;
|
|
204
|
+
if (VipManager.isVip() && time) {
|
|
205
|
+
const date = new Date(time);
|
|
206
|
+
const diff = date.getTime() - new Date().getTime();
|
|
207
|
+
return Math.max(Math.ceil(diff / (24 * 60 * 60 * 1000)), 0);
|
|
208
|
+
}
|
|
209
|
+
return 0;
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
isTrailVip: () => {
|
|
213
|
+
if (VipManager.isForeverVip()) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
if (!VipManager.isVip()) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
const vipType = LoginManager.currentUser()?.AVUser.get('vipType');
|
|
220
|
+
if (vipType?.includes('rc_promo_')) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
refreshVip: async (customerInfo?: CustomerInfo) => {
|
|
227
|
+
try {
|
|
228
|
+
console.log('刷新 VIP');
|
|
229
|
+
if (customerInfo) {
|
|
230
|
+
_customerInfo = customerInfo;
|
|
231
|
+
} else {
|
|
232
|
+
_customerInfo = await Purchases.getCustomerInfo();
|
|
233
|
+
}
|
|
234
|
+
console.log('VIP 信息', _customerInfo?.entitlements?.active);
|
|
235
|
+
console.log('是否是 VIP', VipManager.isVip());
|
|
236
|
+
console.log('VipInfo 过期时间', VipManager.vipEndTime());
|
|
237
|
+
|
|
238
|
+
await updateVipInfo();
|
|
239
|
+
Notification.postNotification('onVipRefresh', {});
|
|
240
|
+
} catch (e) {
|
|
241
|
+
console.error(e);
|
|
242
|
+
Notification.postNotification('onVipRefresh', { e });
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const updateVipInfo = async () => {
|
|
248
|
+
if (!VipManager.isVip() || !LoginManager.isLogin()) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const keys = [];
|
|
253
|
+
const values = [];
|
|
254
|
+
|
|
255
|
+
const vipType = _customerInfo?.entitlements?.active?.vip?.productIdentifier;
|
|
256
|
+
const oldVipType = LoginManager.currentUser()?.AVUser.get('vipType');
|
|
257
|
+
if (vipType && vipType !== oldVipType) {
|
|
258
|
+
keys.push('vipType');
|
|
259
|
+
values.push(vipType);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let vipEndTime;
|
|
263
|
+
if (VipManager.isForeverVip()) {
|
|
264
|
+
vipEndTime = new Date(10413763200000); // 约定 2300-01-01 00:00:00 为永久会员
|
|
265
|
+
} else {
|
|
266
|
+
const expireDate = _customerInfo?.entitlements?.active?.vip?.expirationDate;
|
|
267
|
+
if (expireDate) {
|
|
268
|
+
vipEndTime = new Date(expireDate);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (vipEndTime) {
|
|
272
|
+
const oldVipEndTime = LoginManager.currentUser()?.AVUser.get('vipEndTime');
|
|
273
|
+
if (vipEndTime.getTime() !== oldVipEndTime?.getTime()) {
|
|
274
|
+
keys.push('vipEndTime');
|
|
275
|
+
values.push(vipEndTime);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (keys.length > 0) {
|
|
280
|
+
await LoginManager.batchUpdateUser(keys, values);
|
|
281
|
+
}
|
|
282
|
+
};
|
package/src/index.tsx
CHANGED
|
@@ -8,12 +8,18 @@ const { ReactNativeToolkit } = NativeModules;
|
|
|
8
8
|
|
|
9
9
|
export default ReactNativeToolkit as ReactNativeToolkitType;
|
|
10
10
|
export * from './AppleLoginUtil';
|
|
11
|
+
export * from './ConfigDataModel';
|
|
11
12
|
export * from './DevConfig';
|
|
13
|
+
export * from './Frequence';
|
|
12
14
|
export * from './LoginManager';
|
|
15
|
+
export * from './MessageModel';
|
|
13
16
|
export * from './Notification';
|
|
14
17
|
export * from './PrefData';
|
|
15
18
|
export * from './ReportUtil';
|
|
16
19
|
export * from './SentryManager';
|
|
17
20
|
export * from './SyncPrefData';
|
|
21
|
+
export * from './Tool';
|
|
22
|
+
export * from './VipAndroidManager';
|
|
23
|
+
export * from './VipManager';
|
|
18
24
|
export * from './WeChatLoginUtil';
|
|
19
25
|
export * from './constant';
|