MOWebBaseView.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. //
  2. // MOWebBaseView.m
  3. // MiMoLive
  4. //
  5. // Created by SuperC on 2025/9/11.
  6. //
  7. #import "MOWebBaseView.h"
  8. #import "POWeakWKWebViewScriptMessageHandler.h"
  9. #import "MOWebViewController.h"
  10. #import "MOUploadDeviceTool.h"
  11. // 用于标记webView序号
  12. static int webViewTag = 0;
  13. @interface MOWebBaseView ()<WKNavigationDelegate,WKUIDelegate>
  14. /** 标记WebView序号 */
  15. @property (nonatomic, assign) int webViewTag;
  16. /**记录是否添加了观察者,避免dealloc时释放观察者崩溃*/
  17. @property (nonatomic, assign) BOOL hasAddedObserver;
  18. @end
  19. @implementation MOWebBaseView
  20. - (instancetype)init {
  21. if (self = [super init] ) {
  22. [self setupUI];
  23. }
  24. return self;
  25. }
  26. - (instancetype)initWithFrame:(CGRect)frame{
  27. self = [super initWithFrame:frame];
  28. if (self){
  29. [self setupUI];
  30. }
  31. return self;
  32. }
  33. - (void)setupUI{
  34. [self addSubview:self.poWebView];
  35. [self.poWebView mas_makeConstraints:^(MASConstraintMaker *make) {
  36. make.edges.equalTo(self);
  37. }];
  38. }
  39. - (void)toLoadTheUrl{
  40. //FIXME: 默认缓存策略是NSURLRequestUseProtocolCachePolicy
  41. #if kAPP_Environment == 1
  42. NSURLRequestCachePolicy policy = NSURLRequestUseProtocolCachePolicy;
  43. #elif kAPP_Environment == 2
  44. NSURLRequestCachePolicy policy = NSURLRequestUseProtocolCachePolicy;
  45. // NSURLRequestCachePolicy policy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
  46. if (@available(iOS 16.4,*)) {
  47. [self.poWebView setInspectable:YES];
  48. }
  49. #endif
  50. self.request = [NSURLRequest requestWithURL:self.webUrl cachePolicy:policy timeoutInterval:40];
  51. MOLogV(@"[WebView] init poWebView(%d) url:%@",self.webViewTag,self.webUrl);
  52. [self.poWebView loadRequest:self.request];
  53. }
  54. #pragma mark ========= JS-->OC ===============
  55. - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
  56. //#define kWebCallBack_GetUserInfo @"getUserInfo" //传用户信息
  57. if ([message.name isEqualToString:kWebCallBack_GetUserInfo])
  58. {
  59. MOMeDataInfo *userInfoData = (MOMeDataInfo *)[[MODataCache sharedYYCache] objectForKey:kMineUserInfo];
  60. if(userInfoData){
  61. // ADJAttribution *adjInfo = [Adjust attribution];
  62. userInfoData.token = GetToken;
  63. userInfoData.adid = [MOUploadDeviceTool shareTool].adid;
  64. NSString *versionString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
  65. userInfoData.appVersion = versionString;
  66. NSDictionary *userDict = [userInfoData dictionaryRepresentation];
  67. NSString *jsonString = [userDict modelToJSONString];
  68. NSString *jsString = [NSString stringWithFormat:@"%@(%@)",@"getUserInfoResponse",jsonString];
  69. [self.poWebView evaluateJavaScript:jsString completionHandler:nil];
  70. }
  71. else{
  72. NSString *jsonString = @"{\"follows\":3,\"vip\":{\"giveGiftBag\":false,\"type\":0,\"expireTime\":0,\"giveGaily\":false},\"profile\":{\"id\":\"65d4ba9f097a721b1ef0a8c5\",\"intro\":\"\",\"medals\":[],\"userNo\":\"43999352\",\"bks\":[],\"agoraId\":43999352,\"adornment\":{\"headdressAnno\":false,\"bubbleCode\":0,\"enterBar\":0},\"avatar\":\"https:\\/\\/mimo-live.s3.ap-southeast-3.amazonaws.com\\/av\\/2024\\/52\\/b78\\/fa5f8c804caae17d1635afa724149118.jpg\",\"birthday\":\"1990-01-01\",\"nickname\":\"SuperY\",\"country\":\"ID\",\"gender\":1},\"mobile\":{},\"family\":{\"memberMax\":0,\"totalPower\":0,\"level\":0,\"memberNum\":0,\"weekPower\":0,\"dailyPower\":0},\"wallet\":{\"diamond\":22,\"consumeDiamond\":0,\"goldenBean\":0},\"fansClub\":{\"show\":false,\"level\":0,\"rank\":0,\"members\":0},\"currExp\":49,\"guild\":{\"anchor\":0},\"level\":3,\"friends\":1,\"fans\":1,\"nextExp\":113,\"liveBadge\":{\"type\":0},\"status\":{\"anchor\":true,\"guild\":true,\"mobile\":false,\"fansClub\":false,\"liveDiscount\":true,\"anchorType\":1,\"joinFansClub\":true}}";
  73. NSString *jsString = [NSString stringWithFormat:@"%@(%@)",@"getUserInfoResponse",jsonString];
  74. [self.poWebView evaluateJavaScript:jsString completionHandler:nil];
  75. }
  76. }
  77. //#define kWebCallBack_GetLanguage @"getLanguage" //语言
  78. else if ([message.name isEqualToString:kWebCallBack_GetLanguage]){
  79. NSString *currentLanguage = [NSBundle currentLanguage];
  80. if(currentLanguage.length == 0){
  81. currentLanguage = @"en-us";
  82. }
  83. NSDictionary *userDict = @{@"language":currentLanguage};
  84. NSString *jsonString = [userDict modelToJSONString];
  85. NSString *jsString = [NSString stringWithFormat:@"%@(%@)",@"getLanguageResponse",jsonString];
  86. [self.poWebView evaluateJavaScript:jsString completionHandler:nil];
  87. }
  88. //#define kWebCallBack_GetStatusHeight @"getStatusHeight" //状态栏高度
  89. else if ([message.name isEqualToString:kWebCallBack_GetStatusHeight]){
  90. CGFloat statusHeght = STATUS_BAR_HEIGHT + 44;
  91. NSDictionary *userDict = @{@"statusHeight":@(statusHeght)};
  92. NSString *jsonString = [userDict modelToJSONString];
  93. NSString *jsString = [NSString stringWithFormat:@"%@(%@)",@"getStatusHeightResponse",jsonString];
  94. [self.poWebView evaluateJavaScript:jsString completionHandler:nil];
  95. }
  96. else if ([message.name isEqualToString:@"destroy"]){
  97. }
  98. //#define kWebCallBack_Close @"closeActivity" //关闭界面
  99. else if ([message.name isEqualToString:kWebCallBack_Close]){
  100. }
  101. //#define kWebCallBack_ExportUrl @"exportUrl" //导出链接
  102. else if ([message.name isEqualToString:kWebCallBack_ExportUrl]){
  103. [self toExportUrlWith:message.body];
  104. return;
  105. }
  106. }
  107. /* 页面开始加载 */
  108. - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
  109. NSString *urlString = webView.URL.absoluteString;
  110. MOLogV(@"Navigated to URL: %@", urlString);
  111. }
  112. - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
  113. NSString *urlString = webView.URL.absoluteString;
  114. MOLogV(@"Navigated to URL: %@", urlString);
  115. }
  116. - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
  117. // 在收到响应开始加载后,决定是否跳转
  118. NSString *urlString = webView.URL.absoluteString;
  119. MOLogV(@"Navigated to URL: %@", urlString);
  120. decisionHandler(WKNavigationResponsePolicyAllow);
  121. }
  122. /// 页面加载失败,指初始化第一个页面
  123. - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
  124. {
  125. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(reloadWebViewData) object:nil];
  126. [self performSelector:@selector(reloadWebViewData) withObject:nil afterDelay:2.0];
  127. }
  128. - (void)reloadWebViewData{
  129. #if kAPP_Environment == 1
  130. NSURLRequestCachePolicy policy = NSURLRequestUseProtocolCachePolicy;
  131. #elif kAPP_Environment == 2
  132. NSURLRequestCachePolicy policy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
  133. #endif
  134. self.request = [NSURLRequest requestWithURL:self.webUrl cachePolicy:policy timeoutInterval:40];
  135. MOLogV(@"[WebView] init poWebView(%d) url:%@",self.webViewTag,self.webUrl);
  136. [self.poWebView loadRequest:self.request];
  137. }
  138. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  139. {
  140. if ([keyPath isEqualToString:@"title"])
  141. {
  142. if (object == self.poWebView)
  143. {
  144. }
  145. else
  146. {
  147. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  148. }
  149. }
  150. else
  151. {
  152. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  153. }
  154. }
  155. /* 在发送请求之前,决定是否跳转 */
  156. - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
  157. NSString *urlString = navigationAction.request.URL.absoluteString;
  158. MOLogV(@"mimo-urlString-%@",urlString);
  159. if([urlString containsString:@"mimo://"]){
  160. NSURL *url = [NSURL URLWithString:urlString];
  161. MOLogV(@"mimo-urlString-%@",urlString);
  162. if ([[UIApplication sharedApplication]respondsToSelector:@selector(openURL:options:completionHandler:)])
  163. {
  164. [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
  165. }
  166. else
  167. {
  168. [[UIApplication sharedApplication]openURL:webView.URL];
  169. }
  170. decisionHandler(WKNavigationActionPolicyCancel);
  171. return;
  172. }
  173. MOLogV(@"12313");
  174. decisionHandler(WKNavigationActionPolicyAllow);
  175. }
  176. - (void)toExportUrlWith:(NSString *)jsonStr{
  177. NSDictionary *dict = [self dictionaryWithJsonString:jsonStr];
  178. NSString *theUrl = [MODataManager objectOrNilForKey:@"url" fromDictionary:dict[@"data"]];
  179. NSURL *url = [NSURL URLWithString:theUrl];
  180. if ([[UIApplication sharedApplication] canOpenURL:url]) {
  181. [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
  182. }
  183. }
  184. - (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString{
  185. if(jsonString == nil && jsonString.length == 0){
  186. return nil;
  187. }
  188. NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
  189. NSError *err;
  190. NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
  191. if(err){
  192. MOLogV(@"json解析失败:%@",err);
  193. return nil;
  194. }
  195. return dic;
  196. }
  197. #pragma mark - Lazy
  198. - (WKWebView *)poWebView
  199. {
  200. if (!_poWebView)
  201. {
  202. WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  203. config.selectionGranularity = WKSelectionGranularityDynamic;
  204. config.allowsInlineMediaPlayback = YES;
  205. config.mediaTypesRequiringUserActionForPlayback = NO;
  206. WKPreferences *preferences = [WKPreferences new];
  207. //是否支持JavaScript
  208. preferences.javaScriptEnabled = YES;
  209. //不通过用户交互,是否可以打开窗口
  210. preferences.javaScriptCanOpenWindowsAutomatically = YES;
  211. config.preferences = preferences;
  212. [config.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];
  213. [config setValue:@YES forKey:@"allowUniversalAccessFromFileURLs"];
  214. //新建一个弱引用代理,防止循环引用
  215. POWeakWKWebViewScriptMessageHandler *weakHandler = [[POWeakWKWebViewScriptMessageHandler alloc] initWithSriptMessageHandler:self];
  216. config.userContentController = [self userControllerWithMessageHandler:weakHandler];
  217. _poWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT) configuration:config];
  218. [_poWebView setBackgroundColor:[UIColor whiteColor]];
  219. [_poWebView setOpaque:NO];
  220. WEAKSELF;
  221. [_poWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error)
  222. {
  223. NSString *oldUA = result;
  224. NSString *newUA = [NSString stringWithFormat:@"%@/xiaohui",oldUA];
  225. weakSelf.poWebView.customUserAgent = newUA;
  226. }];
  227. _poWebView.navigationDelegate = self;
  228. _poWebView.UIDelegate = self;
  229. [_poWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
  230. self.webViewTag = webViewTag;
  231. webViewTag++;
  232. self.hasAddedObserver = YES;
  233. _poWebView.scrollView.bounces = NO;//禁用弹性效果
  234. }
  235. return _poWebView;
  236. }
  237. - (WKUserContentController *)userControllerWithMessageHandler:(POWeakWKWebViewScriptMessageHandler *)weakHandler{
  238. WKUserContentController *userController = [[WKUserContentController alloc] init];
  239. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_Close];
  240. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_GetUserInfo];
  241. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_GetStatusHeight];
  242. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_GetLanguage];
  243. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_GetDiamond];
  244. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_ToGetRain];
  245. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_ToSubmitShareLink];
  246. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_TokenExpired];
  247. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_ExportUrl];
  248. //
  249. [userController addScriptMessageHandler:weakHandler name:@"recharge"];
  250. [userController addScriptMessageHandler:weakHandler name:@"clickRecharge"];
  251. [userController addScriptMessageHandler:weakHandler name:@"newTppClose"];
  252. // 2
  253. [userController addScriptMessageHandler:weakHandler name:@"getConfig"];
  254. [userController addScriptMessageHandler:weakHandler name:@"destroy"];
  255. [userController addScriptMessageHandler:weakHandler name:[MOTextAESTools toGetHameRecharge]];
  256. [userController addScriptMessageHandler:weakHandler name:[MOTextAESTools toGetHameLoaded]];
  257. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_ShareToPlatAgency];
  258. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_BindAgencySuccess];
  259. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_ChagneMysteriousStatus];
  260. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_GetBlindBoxScreenParams];
  261. [userController addScriptMessageHandler:weakHandler name:kWebCallBack_SetBlindBoxResult];
  262. return userController;
  263. }
  264. - (void)removeHandler{
  265. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_Close];
  266. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_GetUserInfo];
  267. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_GetStatusHeight];
  268. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_GetLanguage];
  269. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_GetDiamond];
  270. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_ToGetRain];
  271. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_ToSubmitShareLink];
  272. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_TokenExpired];
  273. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_ExportUrl];
  274. //
  275. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:@"recharge"];
  276. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:@"clickRecharge"];
  277. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:@"newTppClose"];
  278. // 2
  279. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:@"getConfig"];
  280. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:@"destroy"];
  281. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:[MOTextAESTools toGetHameRecharge]];
  282. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:[MOTextAESTools toGetHameLoaded]];
  283. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_ShareToPlatAgency];
  284. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_BindAgencySuccess];
  285. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_ChagneMysteriousStatus];
  286. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_GetBlindBoxScreenParams];
  287. [_poWebView.configuration.userContentController removeScriptMessageHandlerForName:kWebCallBack_SetBlindBoxResult];
  288. }
  289. - (void)dealloc{
  290. [self removeHandler];
  291. }
  292. @end