fix: 修复 WKWebView 白屏及 finishActivity JS Bridge 失效问题
- XJBaseWebViewVC: 补全 finishActivity 消息分发,基类默认实现改为 pop 返回 - XJBaseWebViewVC: 新增 decidePolicyForNavigationAction 拦截非 HTTP scheme(alipay:// 等),避免 WKWebView 加载失败导致白屏 - XJBaseWebViewVC: 新增 webViewWebContentProcessDidTerminate,进程被系统杀死后自动 reload - XJBankWebDetailViewController: 移除重复的 finishActivity override,复用基类 pop 逻辑 - AppDelegate: 移除导致启动卡顿的 WKWebView 预热代码 - HomeV2: 将 Controllview 相关文件移入 Controllview 子目录,整理目录结构
This commit is contained in:
@@ -154,8 +154,10 @@
|
||||
}
|
||||
|
||||
- (void)finishActivity {
|
||||
|
||||
|
||||
// H5 调用 finishActivity 的默认行为:pop 返回上一页
|
||||
// 语义等同于 Android 的 finish(),即关闭当前页面
|
||||
// 子类如需特殊处理(如 dismiss、发通知等),override 此方法即可
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +191,7 @@
|
||||
WkJSMessageType messageType = [[dic objectForKey:@"messageType"] intValue];
|
||||
switch (messageType) {
|
||||
case WkJSMessageTypeBack:{
|
||||
// [self.navigationController popViewControllerAnimated:YES];
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -199,6 +201,12 @@
|
||||
|
||||
} else if ([message.name isEqualToString:@"htmlBack"]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"fromWebToReloadData" object:nil];
|
||||
|
||||
} else if ([message.name isEqualToString:@"finishActivity"]) {
|
||||
// JS 调用 window.webkit.messageHandlers.finishActivity.postMessage({}) 时触发
|
||||
// 调用 finishActivity 方法,子类可 override 实现各自的关闭逻辑
|
||||
// 基类默认实现为空,不做任何操作
|
||||
[self finishActivity];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +238,65 @@
|
||||
[self hiddenAllMBProgressHUD];
|
||||
}
|
||||
|
||||
#pragma mark - 白屏修复
|
||||
|
||||
/**
|
||||
* 拦截所有导航请求,处理非 HTTP/HTTPS scheme。
|
||||
*
|
||||
* 问题根源:
|
||||
* 银行 H5 点击支付/跳转按钮时,会触发 alipay:// weixin:// tel:// 等 URL Scheme。
|
||||
* WKWebView 默认会尝试自己加载这些 scheme,加载失败后清空页面内容 → 永久白屏。
|
||||
*
|
||||
* 解决方案:
|
||||
* 在此方法中拦截非 HTTP/HTTPS 的请求,交由系统(UIApplication)处理,
|
||||
* WKWebView 自身取消该次导航,页面内容保持不变。
|
||||
*/
|
||||
- (void)webView:(WKWebView *)webView
|
||||
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
|
||||
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
|
||||
|
||||
NSURL *url = navigationAction.request.URL;
|
||||
NSString *scheme = url.scheme.lowercaseString;
|
||||
|
||||
// HTTP / HTTPS:正常加载,交给 WKWebView 处理
|
||||
if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
return;
|
||||
}
|
||||
|
||||
// about:blank:WKWebView 内部使用,直接放行
|
||||
if ([scheme isEqualToString:@"about"]) {
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他 scheme(alipay:// weixin:// tel:// mailto:// 等):
|
||||
// 交由系统打开对应 App 或拨号,WKWebView 取消此次导航,避免白屏
|
||||
if ([[UIApplication sharedApplication] canOpenURL:url]) {
|
||||
[[UIApplication sharedApplication] openURL:url
|
||||
options:@{}
|
||||
completionHandler:nil];
|
||||
}
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
}
|
||||
|
||||
/**
|
||||
* WebContent 进程被系统终止时的兜底处理。
|
||||
*
|
||||
* 触发场景:
|
||||
* 设备内存严重不足时,系统会强制 kill 掉 WKWebView 的 WebContent 进程。
|
||||
* 此时 WKWebView 会立即变成空白页,且无法响应任何操作。
|
||||
* 若不处理,用户只能退出页面重新进入。
|
||||
*
|
||||
* 解决方案:
|
||||
* 检测到进程终止后,重新加载当前 URL,让用户无感知恢复。
|
||||
*/
|
||||
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
|
||||
NSLog(@"[XJBaseWebViewVC] WebContent 进程被系统终止,自动 reload");
|
||||
// 重新加载,恢复页面内容
|
||||
[webView reload];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// XJBankWebDetailViewController.h
|
||||
// XinjiangProject
|
||||
//
|
||||
// Created by Apple on 2026/3/11.
|
||||
//
|
||||
|
||||
#import "XJBaseWebViewVC.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface XJBankWebDetailViewController : XJBaseWebViewVC
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// XJBankWebDetailViewController.m
|
||||
// XinjiangProject
|
||||
//
|
||||
// Created by Apple on 2026/3/11.
|
||||
//
|
||||
|
||||
#import "XJBankWebDetailViewController.h"
|
||||
|
||||
@interface XJBankWebDetailViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation XJBankWebDetailViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.isHidenNaviBar = true;
|
||||
[self.wkWebView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.left.right.mas_offset(0);
|
||||
make.bottom.mas_offset(-SafetyAreaHeight);
|
||||
}];
|
||||
}
|
||||
|
||||
// finishActivity 行为与基类一致(pop 返回),无需 override
|
||||
// 基类 XJBaseWebViewVC 已实现默认 pop 逻辑
|
||||
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
+144
-34
@@ -4,7 +4,7 @@
|
||||
//
|
||||
// Created by Apple on 2026/2/9.
|
||||
//
|
||||
|
||||
#import "XJBankWebDetailViewController.h"
|
||||
#import "XJHomePageV2ViewController.h"
|
||||
#import "QuestionViewController.h"
|
||||
#import "HealthyQuestionTable.h"
|
||||
@@ -76,6 +76,9 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
|
||||
@property (nonatomic, strong) SDCycleScrollView * AIBannerImage;
|
||||
|
||||
//加密后的字符串
|
||||
@property (nonatomic, copy) NSString * secretString;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -123,6 +126,7 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
[self initCompleteBlock];
|
||||
[self configLocationManager];
|
||||
[self reGeocodeAction];
|
||||
|
||||
//请求手表数据
|
||||
// 4. 添加 V2TIMSDKListener 的事件监听器,self 是 id<V2TIMSDKListener> 的实现类,如果您不需要监听 IM SDK 的事件,这个步骤可以忽略。
|
||||
[[V2TIMManager sharedInstance] addIMSDKListener:self];
|
||||
@@ -172,10 +176,9 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
//请求消息列表
|
||||
[self getMessageListData];
|
||||
[self getUserWatchData];
|
||||
[self getWebKeySecret];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -343,6 +346,37 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
[searchApi getHomeWatchData:parmDic];
|
||||
}
|
||||
|
||||
#pragma mark: 请求key的加密
|
||||
- (void)getWebKeySecret {
|
||||
|
||||
NSString * scheme = SCHEME;
|
||||
|
||||
NSString * host;
|
||||
|
||||
#if DEBUG
|
||||
host = @"xj-api.mcrm.vip";
|
||||
|
||||
|
||||
#else
|
||||
host = @"api-jkglpt.iosp.ydpt.tech";
|
||||
|
||||
#endif
|
||||
|
||||
NSString * token = User_Token;
|
||||
|
||||
NSString * keyStirng = [NSString stringWithFormat:@"scheme=%@&host=%@&tokenF=%@",scheme,host,token];
|
||||
|
||||
NSMutableDictionary * parmDic = [[NSMutableDictionary alloc] init];
|
||||
|
||||
[parmDic setObject:keyStirng forKey:@"str"];
|
||||
|
||||
XJPNetAPI * searchApi = [[XJPNetAPI alloc] init:self tag:@"SECRET" NeedToken:@""];
|
||||
|
||||
[searchApi getWebNeedEncryptionKey:parmDic];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void)Failed:(NSString*)message tag:(NSString*)tag
|
||||
{
|
||||
|
||||
@@ -411,9 +445,6 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
[self getData];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ([tag isEqualToString:@"IMAPI"]) {
|
||||
@@ -444,9 +475,6 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
|
||||
}];
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
if ([tag isEqualToString:@"SMALLHELP"]) {
|
||||
|
||||
@@ -644,6 +672,17 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
|
||||
self.topView.watchArray = sortedArray;
|
||||
}
|
||||
if ([tag isEqualToString:@"SECRET"]) {
|
||||
DLog(@"%@",response)
|
||||
NSDictionary * responseDic = response;
|
||||
|
||||
if ([responseDic.allKeys containsObject:@"encryptData"]) {
|
||||
self.secretString = responseDic[@"encryptData"];
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//是否需要更新
|
||||
@@ -722,26 +761,26 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
|
||||
[self.navigationController pushViewController:foundVC animated:true];
|
||||
}
|
||||
|
||||
- (void)smallQuestionAction {
|
||||
|
||||
if ([ESCTUIManager TUIUserStatus] == false) {
|
||||
|
||||
|
||||
[self loginImAccount];
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary * dic = [[NSMutableDictionary alloc] init];
|
||||
|
||||
[self showMBProgressHUDWithString:@"咨询中,请稍候..." autoHidden:NO];
|
||||
XJPNetAPI * searchApi = [[XJPNetAPI alloc] init:self tag:@"SMALLHELP" NeedToken:@""];
|
||||
|
||||
[searchApi postSmallHelpGroup:dic];
|
||||
|
||||
|
||||
|
||||
}
|
||||
//
|
||||
//- (void)smallQuestionAction {
|
||||
//
|
||||
// if ([ESCTUIManager TUIUserStatus] == false) {
|
||||
//
|
||||
//
|
||||
// [self loginImAccount];
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// NSMutableDictionary * dic = [[NSMutableDictionary alloc] init];
|
||||
//
|
||||
// [self showMBProgressHUDWithString:@"咨询中,请稍候..." autoHidden:NO];
|
||||
// XJPNetAPI * searchApi = [[XJPNetAPI alloc] init:self tag:@"SMALLHELP" NeedToken:@""];
|
||||
//
|
||||
// [searchApi postSmallHelpGroup:dic];
|
||||
//
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
- (void)myQuestionAction {
|
||||
|
||||
@@ -903,13 +942,62 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
}];
|
||||
//代理
|
||||
self.homeTable.headDelegate = self;
|
||||
kWeakSelf(self);
|
||||
self.homeTable.tableBlock = ^(HomeQusetionRecordsModel * _Nonnull model) {
|
||||
weakself.recomendModel = model;
|
||||
|
||||
if(![HQCommonUtils isLogin]) {
|
||||
KPostNotification(KNotificationLoginStateChange, @NO);
|
||||
return;
|
||||
}
|
||||
|
||||
//1图文 2视频
|
||||
if ([model.contentType intValue] == 2) {
|
||||
|
||||
XJDoctorMainViewController * doctorVC = [[XJDoctorMainViewController alloc] init];
|
||||
doctorVC.yuyue_id = model.records_id;
|
||||
doctorVC.popType = 1;
|
||||
[weakself.navigationController pushViewController:doctorVC animated:YES];
|
||||
}
|
||||
if ([model.contentType intValue] == 1) {
|
||||
|
||||
if ([TUILogin isUserLogined]) {
|
||||
ChatViewController * chatVC = [[ChatViewController alloc] init];
|
||||
chatVC.isGroupID = YES;
|
||||
chatVC.chatID = model.imId ;
|
||||
chatVC.eableSendReport = true;
|
||||
chatVC.eablehaveHelathData = false;
|
||||
chatVC.navTitle = @"图文咨询";
|
||||
chatVC.isVideo = NO;
|
||||
chatVC.pictureEnd_id = model.records_id;
|
||||
chatVC.questionType = 2;
|
||||
chatVC.medicalRecordsId = model.memberId;
|
||||
if ([model.contentStatus intValue] == 5) {
|
||||
chatVC.isEveal = true;
|
||||
}else
|
||||
{
|
||||
chatVC.isEveal = false;
|
||||
}
|
||||
if ([model.contentStatus intValue] >=4 ) {
|
||||
chatVC.endRecordType = 100;
|
||||
}
|
||||
[weakself.navigationController pushViewController:chatVC animated:YES];
|
||||
}else
|
||||
{
|
||||
if ([HQCommonUtils isLogin]) {
|
||||
[weakself loginImAccountList];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//监听
|
||||
[self.homeTable addObserver:self
|
||||
forKeyPath:@"contentSize"
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:nil];
|
||||
kWeakSelf(self);
|
||||
|
||||
self.homeTable.lookMoreBlock = ^{
|
||||
if(![HQCommonUtils isLogin]) {
|
||||
@@ -988,6 +1076,7 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
}];
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 计算table的高度
|
||||
@@ -1084,10 +1173,31 @@ static CGFloat const kEmptyTableMinHeight = 250; // 或屏幕高度的一半
|
||||
}
|
||||
if (type == 3) {
|
||||
|
||||
EmptyFunctionDevelopmentVC * vc = [[EmptyFunctionDevelopmentVC alloc] init];
|
||||
vc.navigationItem.title = @"健康银行";
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
// EmptyFunctionDevelopmentVC * vc = [[EmptyFunctionDevelopmentVC alloc] init];
|
||||
// vc.navigationItem.title = @"健康银行";
|
||||
// [self.navigationController pushViewController:vc animated:YES];
|
||||
if(![HQCommonUtils isLogin]) {
|
||||
KPostNotification(KNotificationLoginStateChange, @NO);
|
||||
return;
|
||||
}
|
||||
if (ValidStr(self.secretString)) {
|
||||
[self showMBProgressHUDOnlyWithString:@"网络异常请稍候再试~"];
|
||||
[self getWebKeySecret];
|
||||
return;
|
||||
}
|
||||
XJBankWebDetailViewController * bankVC = [[XJBankWebDetailViewController alloc] init];
|
||||
|
||||
NSString * urlString;
|
||||
#if DEBUG
|
||||
urlString = @"https://gstest.superwx.cn/healthbank/index.html?";
|
||||
|
||||
|
||||
#else
|
||||
urlString = @"https://console-jkglpt.iosp.ydpt.tech/hb/healthweb/index.html";
|
||||
|
||||
#endif
|
||||
bankVC.webUrl = [NSString stringWithFormat:@"%@?param=%@",urlString,self.secretString];
|
||||
[self.navigationController pushViewController:bankVC animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user