基础库
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.
 
 
 
 
 

442 lines
17 KiB

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