基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

430 lines
16 KiB

  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter_alibc/alibc_model.dart';
  4. import 'package:flutter_alibc/flutter_alibc.dart';
  5. import 'package:fluttertoast/fluttertoast.dart';
  6. import 'package:jdsdk/jdsdk.dart';
  7. import 'package:url_launcher/url_launcher.dart';
  8. import 'package:zhiying_comm/models/user/user_info_model.dart';
  9. import 'package:zhiying_comm/util/dialog/loading/loading.dart';
  10. import 'package:zhiying_comm/util/empty_util.dart';
  11. import 'package:zhiying_comm/util/global_config.dart';
  12. import 'package:zhiying_comm/util/log/let_log.dart';
  13. import 'package:zhiying_comm/util/net_util.dart';
  14. import 'package:zhiying_comm/util/pdd_auth/pdd_auth.dart';
  15. import 'package:zhiying_comm/util/taobao/taobao_auth.dart';
  16. import 'package:zhiying_comm/util/turn_chain/turn_chain_dialog_repository.dart';
  17. import 'package:zhiying_comm/util/turn_chain/turn_chain_style_model.dart';
  18. import '../router_util.dart';
  19. import 'turn_chain_dialog.dart';
  20. import 'package:zhiying_comm/util/shared_prefe_util.dart';
  21. class TurnChainUtil {
  22. ///
  23. /// 跳转app或者打开url进行领券
  24. /// userInfoModel: 用户登陆的带有token 与 淘宝是否授权的 model类
  25. /// provider: 商品的渠道
  26. /// data: 转链需要的请求参数
  27. ///
  28. /// 一些常用的APP的 URL scheme:
  29. /// 来源:https://blog.csdn.net/jdazy/article/details/79208754
  30. /// QQ: mqq://
  31. /// 微信: weixin://
  32. /// 京东: openapp.jdmobile://
  33. /// 淘宝: taobao://
  34. /// 美团: imeituan://
  35. /// 点评: dianping://
  36. /// 1号店: wccbyihaodian://
  37. /// 支付宝: alipay://
  38. /// 微博: sinaweibo://
  39. /// 腾讯微博: TencentWeibo://
  40. /// weico微博: weico://
  41. /// 知乎: zhihu://
  42. /// 豆瓣fm: doubanradio://
  43. /// 网易公开课: ntesopen://
  44. /// Chrome: googlechrome://
  45. /// QQ浏览器: mqqbrowser://
  46. /// uc浏览器: ucbrowser://
  47. /// 搜狗浏览器: SogouMSE://
  48. /// 百度地图: baidumap:// bdmap://
  49. /// 优酷: youku://
  50. /// 人人: renren://
  51. /// 我查查: wcc://
  52. /// 有道词典: yddictproapp://
  53. /// 微盘: sinavdisk://
  54. /// 名片全能王: camcard://
  55. ///
  56. static Future<void> openReceiveCoupon(BuildContext context, UserInfoModel userInfoModel, String goodsId, String provider, Map<String, dynamic> data, {bool isFree = false}) async {
  57. /// iOS 审核状态
  58. // String is_ios_review = await SharedPreferencesUtil.getStringValue(GlobalConfig.IS_IOS_REVIEW, defaultVal: '0');
  59. /// 1、先判断是否登陆
  60. if (EmptyUtil.isEmpty(userInfoModel) || EmptyUtil.isEmpty(userInfoModel?.token)) {
  61. RouterUtil.goLogin(context);
  62. return;
  63. }
  64. /// 2、如果是淘宝或者天猫,判断是否授权
  65. ///
  66. /// ⚠️ 因业务修改,淘宝或者天猫每次都必须请求网络请求状态
  67. // if ((provider == GlobalConfig.PROVIDER_TB || provider == GlobalConfig.PROVIDER_TM ) && !userInfoModel.isTBAuth) {
  68. // TaobaoAuth.auth(context);
  69. // return;
  70. // }
  71. if (provider == GlobalConfig.PROVIDER_TB || provider == GlobalConfig.PROVIDER_TM ) {
  72. bool isAuth = await TaobaoAuth.auth(context);
  73. if (!isAuth) return;
  74. }
  75. /// 3、获取转链,进行跳转
  76. Map<String, dynamic> result = await getTurnChainResult(context, goodsId, provider, data, isShare: false, isFree: isFree);
  77. if (!EmptyUtil.isEmpty(result)) {
  78. String openAppUrl = result['open_app_url'];
  79. String appUrl = result['app_url'];
  80. String webUrl = result['no_open_app_url'];
  81. bool jumpResult = await jumpNative(context, provider: provider, openAppUrl: openAppUrl, appUrl: appUrl, webUrl: webUrl);
  82. if (!jumpResult) {
  83. Fluttertoast.cancel();
  84. Fluttertoast.showToast(msg: '购买链接不存在');
  85. }
  86. // /// 4、根据渠道进行不同的跳转
  87. // switch (provider) {
  88. // case GlobalConfig.PROVIDER_TB:
  89. // case GlobalConfig.PROVIDER_TM:
  90. // if (!EmptyUtil.isEmpty(openAppUrl)) {
  91. // TradeResult tradeResult;
  92. // if (Platform.isAndroid) {
  93. // // print("跳转链接"+openAppUrl);
  94. // tradeResult = await FlutterAlibc.openByUrl(url: openAppUrl, backUrl: "alisdk://");
  95. // } else if (Platform.isIOS) {
  96. // if (is_ios_review == '1') {
  97. // print('iOS审核:' + is_ios_review);
  98. // RouterUtil.openWebview(webUrl, context);
  99. // } else {
  100. // tradeResult = await FlutterAlibc.openByUrl(url: openAppUrl);
  101. // }
  102. // }
  103. // Logger.debug('taobao result = ${tradeResult.errorCode} ${tradeResult.errorMessage} ');
  104. // } else if (!EmptyUtil.isEmpty(webUrl)) {
  105. // RouterUtil.openWebview(webUrl, context);
  106. // } else {
  107. // Fluttertoast.cancel();
  108. // Fluttertoast.showToast(msg: '购买链接不存在');
  109. // }
  110. //
  111. // break;
  112. // case GlobalConfig.PROVIDER_JD:
  113. // String tempURLScheme1 = 'openapp.jdmobile://virtual?params=%';
  114. // String tempURLScheme2 = 'openapp.jdmobile://';
  115. // if (!EmptyUtil.isEmpty(openAppUrl) && await canLaunch(tempURLScheme1) || await canLaunch(tempURLScheme2)) {
  116. // Jdsdk.openUrl(url: openAppUrl);
  117. // } else if (!EmptyUtil.isEmpty(webUrl)) {
  118. // RouterUtil.openWebview(webUrl, context);
  119. // } else {
  120. // Fluttertoast.cancel();
  121. // Fluttertoast.showToast(msg: '购买链接不存在');
  122. // }
  123. // break;
  124. // case GlobalConfig.PROVIDER_KL:
  125. // case GlobalConfig.PROVIDER_PDD:
  126. // case GlobalConfig.PROVIDER_SN:
  127. // bool launchable = await canLaunch(appUrl);
  128. // if (Platform.isIOS) {
  129. // launchable = await launch(appUrl);
  130. // }
  131. // if (launchable) {
  132. // if (!Platform.isIOS) {
  133. // if (appUrl.startsWith("suning")) {
  134. // RouterUtil.openWebview(webUrl, context);
  135. // } else {
  136. // RouterUtil.openWebview(webUrl, context);
  137. // }
  138. // }
  139. // } else if (!EmptyUtil.isEmpty(webUrl)) {
  140. // Logger.log('打开${provider} webUrl, url = ${webUrl}');
  141. // RouterUtil.openWebview(webUrl, context);
  142. // } else {
  143. // Fluttertoast.cancel();
  144. // Fluttertoast.showToast(msg: '购买链接不存在');
  145. // }
  146. // break;
  147. // case GlobalConfig.PROVIDER_VIP:
  148. // bool launchable = await canLaunch(appUrl);
  149. // if (Platform.isIOS) {
  150. // launchable = await launch(appUrl);
  151. // }
  152. // if (launchable) {
  153. // if (!Platform.isIOS) {
  154. // await launch(appUrl);
  155. // }
  156. // } else if (!EmptyUtil.isEmpty(webUrl)) {
  157. // Logger.log('打开${provider} webUrl, url = ${webUrl}');
  158. // RouterUtil.openWebview(webUrl, context);
  159. // } else {
  160. // Fluttertoast.cancel();
  161. // Fluttertoast.showToast(msg: '购买链接不存在');
  162. // }
  163. // break;
  164. // default:
  165. // if (!EmptyUtil.isEmpty(openAppUrl)) {
  166. // bool launchable = await canLaunch(appUrl);
  167. // if (launchable) {
  168. // launchable = await launch(appUrl);
  169. // }
  170. // if (launchable) {
  171. // if (!Platform.isIOS) {
  172. // RouterUtil.openWebview(webUrl, context);
  173. // }
  174. // } else if (!EmptyUtil.isEmpty(webUrl)) {
  175. // Logger.log('打开${provider} webUrl, url = ${webUrl}');
  176. // RouterUtil.openWebview(webUrl, context);
  177. // } else {
  178. // Fluttertoast.cancel();
  179. // Fluttertoast.showToast(msg: '购买链接不存在');
  180. // }
  181. // } else {
  182. // Fluttertoast.cancel();
  183. // Fluttertoast.showToast(msg: '购买链接不存在');
  184. // }
  185. // break;
  186. // }
  187. } else {
  188. Fluttertoast.cancel();
  189. Fluttertoast.showToast(msg: '购买链接不存在');
  190. }
  191. }
  192. ///
  193. /// 跳转原生或者webView打开购买链接
  194. ///
  195. /// provider: 商品渠道
  196. /// openAppUrl: 打开商品链接
  197. /// appUrl: 打开商品链接,不是Http开头,类似 taobao://, opennapp.jdxxx://
  198. /// webUrl: 打开商品WebView链接
  199. ///
  200. static Future<bool> jumpNative(BuildContext context, {String provider = GlobalConfig.PROVIDER_TB, String openAppUrl, String appUrl, String webUrl}) async {
  201. bool rlt = false;
  202. ///iOS 审核状态
  203. String isIosReview = await SharedPreferencesUtil.getStringValue(GlobalConfig.IS_IOS_REVIEW, defaultVal: '0');
  204. /// 4、根据渠道进行不同的跳转
  205. switch (provider) {
  206. case GlobalConfig.PROVIDER_TB:
  207. case GlobalConfig.PROVIDER_TM:
  208. if (!EmptyUtil.isEmpty(openAppUrl)) {
  209. TradeResult tradeResult;
  210. if (Platform.isAndroid) {
  211. tradeResult = await FlutterAlibc.openByUrl(url: openAppUrl, backUrl: "alisdk://");
  212. rlt = true;
  213. } else if (Platform.isIOS) {
  214. if (isIosReview == '1') {
  215. print('iOS审核:' + isIosReview);
  216. RouterUtil.openWebview(webUrl, context);
  217. rlt = true;
  218. } else {
  219. tradeResult = await FlutterAlibc.openByUrl(url: openAppUrl);
  220. rlt = true;
  221. }
  222. }
  223. Logger.debug('taobao result = ${tradeResult.errorCode} ${tradeResult.errorMessage} ');
  224. } else if (!EmptyUtil.isEmpty(webUrl)) {
  225. RouterUtil.openWebview(webUrl, context);
  226. rlt = true;
  227. } else {
  228. rlt = false;
  229. }
  230. break;
  231. case GlobalConfig.PROVIDER_JD:
  232. String tempURLScheme1 = 'openapp.jdmobile://virtual?params=%';
  233. String tempURLScheme2 = 'openapp.jdmobile://';
  234. if (!EmptyUtil.isEmpty(openAppUrl) && await canLaunch(tempURLScheme1) || await canLaunch(tempURLScheme2)) {
  235. Jdsdk.openUrl(url: openAppUrl);
  236. rlt = true;
  237. } else if (!EmptyUtil.isEmpty(webUrl)) {
  238. RouterUtil.openWebview(webUrl, context);
  239. rlt = true;
  240. } else {
  241. rlt = false;
  242. }
  243. break;
  244. case GlobalConfig.PROVIDER_KL:
  245. case GlobalConfig.PROVIDER_PDD:
  246. case GlobalConfig.PROVIDER_SN:
  247. bool launchable = await canLaunch(appUrl);
  248. if (Platform.isIOS) {
  249. launchable = await launch(appUrl);
  250. }
  251. if (launchable) {
  252. if (!Platform.isIOS) {
  253. if (appUrl.startsWith("suning")) {
  254. RouterUtil.openWebview(webUrl, context);
  255. rlt = true;
  256. } else {
  257. RouterUtil.openWebview(webUrl, context);
  258. rlt = true;
  259. }
  260. }
  261. } else if (!EmptyUtil.isEmpty(webUrl)) {
  262. Logger.log('打开${provider} webUrl, url = ${webUrl}');
  263. RouterUtil.openWebview(webUrl, context);
  264. rlt = true;
  265. } else {
  266. rlt = false;
  267. }
  268. break;
  269. case GlobalConfig.PROVIDER_VIP:
  270. bool launchable = await canLaunch(appUrl);
  271. if (Platform.isIOS) {
  272. launchable = await launch(appUrl);
  273. }
  274. if (launchable) {
  275. if (!Platform.isIOS) {
  276. await launch(appUrl);
  277. rlt = true;
  278. }
  279. } else if (!EmptyUtil.isEmpty(webUrl)) {
  280. Logger.log('打开${provider} webUrl, url = ${webUrl}');
  281. RouterUtil.openWebview(webUrl, context);
  282. rlt = true;
  283. } else {
  284. rlt = false;
  285. }
  286. break;
  287. default:
  288. if (!EmptyUtil.isEmpty(openAppUrl)) {
  289. bool launchable = await canLaunch(appUrl);
  290. if (launchable) {
  291. launchable = await launch(appUrl);
  292. }
  293. if (launchable) {
  294. if (!Platform.isIOS) {
  295. RouterUtil.openWebview(webUrl, context);
  296. rlt = true;
  297. }
  298. } else if (!EmptyUtil.isEmpty(webUrl)) {
  299. Logger.log('打开${provider} webUrl, url = ${webUrl}');
  300. RouterUtil.openWebview(webUrl, context);
  301. rlt = true;
  302. } else {
  303. rlt = false;
  304. }
  305. } else {
  306. rlt = false;
  307. }
  308. break;
  309. }
  310. return Future.value(rlt);
  311. }
  312. ///
  313. /// 获取分享的转链
  314. /// userInfoModel: 用户登陆的带有token 与 淘宝是否授权的 model类
  315. /// provider: 商品的渠道
  316. /// data: 转链需要的请求参数
  317. ///
  318. /// 返回参数: 只需要获取返回结果的 open_app_url 值即可。
  319. /// 例如: Map<String, dynamic> result = await getShareTurnChain(context, _user, provider, data);
  320. /// String buyUrl = result['open_app_url']
  321. ///
  322. static Future<Map<String, dynamic>> getShareTurnChain(BuildContext context, UserInfoModel userInfoModel, String goodsId, String provider, Map<String, dynamic> data) async {
  323. /// 1、先判断是否登陆
  324. if (EmptyUtil.isEmpty(userInfoModel) || EmptyUtil.isEmpty(userInfoModel?.token)) {
  325. RouterUtil.goLogin(context);
  326. return null;
  327. }
  328. /// 2、如果是淘宝,判断是否授权
  329. // if ((provider == GlobalConfig.PROVIDER_TB || provider == GlobalConfig.PROVIDER_TM) && !userInfoModel.isTBAuth) {
  330. // TaobaoAuth.auth(context);
  331. // return null;
  332. // }
  333. /// ⚠️ 因业务修改,淘宝或者天猫每次都必须请求网络请求状态
  334. if (provider == GlobalConfig.PROVIDER_TB || provider == GlobalConfig.PROVIDER_TM ) {
  335. bool isAuth = await TaobaoAuth.auth(context);
  336. if (!isAuth) return null;
  337. }
  338. /// 2.5 如果是拼多多,判断是否需要授权
  339. if(provider == GlobalConfig.PROVIDER_PDD) {
  340. // 如果为true,说明需要进行授权,停止执行。
  341. bool result = await PddAuth.auth(context);
  342. if (result) return null;
  343. }
  344. /// 3、获取转链的结果
  345. Map<String, dynamic> result = await getTurnChainResult(context, goodsId, provider, data, isShare: true);
  346. if (!EmptyUtil.isEmpty(result) && !EmptyUtil.isEmpty(result['open_app_url'])) {
  347. return result;
  348. }
  349. Fluttertoast.cancel();
  350. Fluttertoast.showToast(msg: '购买链接不存在');
  351. return null;
  352. }
  353. ///
  354. /// 获取跳转的dialog样式
  355. ///
  356. static Future<dynamic> getCacheTurnChainDialogStyle(String goodsId, String provider, String commission, String coupon) async {
  357. TurnChainDialogRepository repository = TurnChainDialogRepository();
  358. var result = await repository.fetchCacheData(goodsId, provider, commission, coupon);
  359. if (!EmptyUtil.isEmpty(result)) {
  360. return result;
  361. }
  362. return null;
  363. }
  364. ///
  365. /// 缓存跳转的dialog样式
  366. ///
  367. static Future<bool> cacheTurnChainDialogStyle(String goodsId, String provider, String commission, String coupon) async {
  368. TurnChainDialogRepository repository = TurnChainDialogRepository();
  369. bool result = await repository.cacheData(goodsId, provider, commission, coupon);
  370. return result;
  371. }
  372. ///
  373. /// 接口文档:https://www.showdoc.com.cn/1003739271891029?page_id=5760575662067820
  374. /// 根据商品id等信息,获取领券或者分享的转链接
  375. ///
  376. ///
  377. static Future<Map<String, dynamic>> getTurnChainResult(BuildContext context, String goodsId, String provider, Map<String, dynamic> data,
  378. {bool isShare = false, bool isFree = false}) async {
  379. try {
  380. TurnChainDialogRepository repository = TurnChainDialogRepository();
  381. if (!EmptyUtil.isEmpty(context) && !EmptyUtil.isEmpty(provider) && !EmptyUtil.isEmpty(data) && !EmptyUtil.isEmpty('gid')) {
  382. TurnChainStyleModel model = await repository.fetchCacheData(goodsId, provider, data['commission'], data['coupon_price']);
  383. // 设置是否分享还是转链
  384. data['is_share'] = isShare ? '1' : '0';
  385. ///1为免单,0为普通
  386. data['is_free'] = (isFree ?? false) ? "1" : "0";
  387. (isFree ?? false) ? print("免单") : print("普通");
  388. if (EmptyUtil.isEmpty(model)) {
  389. // 开启loading
  390. Loading.show(context);
  391. } else {
  392. TurnChainLoading.show(context, model);
  393. }
  394. var result = await NetUtil.post('/api/v1/convert/$provider', params: data, method: NetMethod.POST);
  395. if (EmptyUtil.isEmpty(model)) {
  396. // 关闭loading
  397. Loading.dismiss();
  398. } else {
  399. TurnChainLoading.dismiss();
  400. }
  401. if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
  402. return result[GlobalConfig.HTTP_RESPONSE_KEY_DATA];
  403. }
  404. }
  405. } catch (e, s) {
  406. Logger.error(e, s);
  407. }
  408. return null;
  409. }
  410. }