KSBaseWKWebViewController.m 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. //
  2. // KSBaseWKWebViewController.m
  3. // KulexiuForTeacher
  4. //
  5. // Created by Kyle on 2022/3/17.
  6. //
  7. #import "KSBaseWKWebViewController.h"
  8. #import "JPUSHService.h"
  9. #import "LoginViewController.h"
  10. #import "AppDelegate.h"
  11. #import "CustomNavViewController.h"
  12. #import <RongIMKit/RongIMKit.h>
  13. #import "UIDevice+TFDevice.h"
  14. #import "KSPremissionAlert.h"
  15. #import "RecordCheckManager.h"
  16. #import "KSLocalWebViewController.h"
  17. #import "RCConnectionManager.h"
  18. #import "KSAccompanyWebViewController.h"
  19. #import "KSChatConversationViewController.h"
  20. #import "KSOrderManager.h"
  21. @interface KSBaseWKWebViewController ()
  22. @property (nonatomic, assign) BOOL isOutLink; // 外部链接
  23. @property (nonatomic,weak) CALayer *progressLayer;
  24. @property (nonatomic, strong) NSString *currerntURL; // 当前web URL
  25. @property (nonatomic, assign) BOOL hasModify;
  26. @property (nonatomic, assign) BOOL hasChangeSource; // 是否切换了亮屏,横屏等配置
  27. @property (nonatomic, assign) BOOL landScape;
  28. @end
  29. @implementation KSBaseWKWebViewController
  30. - (void)viewDidLoad {
  31. [super viewDidLoad];
  32. // Do any additional setup after loading the view.
  33. self.ks_prefersNavigationBarHidden = YES; // 隐藏导航栏,其他事件额外处理
  34. [self initWebView];
  35. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(operationDealCallbackMessage:) name:DEALCALLBACKNOTICIFATION object:nil];
  36. }
  37. - (void)operationDealCallbackMessage:(NSNotification *)notification {
  38. NSString *status = [notification object];
  39. NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
  40. [sendParm setValue:@"paymentOperation" forKey:@"api"];
  41. [sendParm setValue:status forKey:@"status"];
  42. [self postMessage:sendParm];
  43. }
  44. - (void)setParmDic:(NSDictionary *)parmDic {
  45. _parmDic = parmDic;
  46. _hasChangeSource = YES;
  47. BOOL isOpenLight = [parmDic boolValueForKey:@"isOpenLight"];
  48. [[UIApplication sharedApplication] setIdleTimerDisabled:isOpenLight];
  49. // 横竖屏
  50. NSInteger orientation = [parmDic integerValueForKey:@"orientation"];
  51. BOOL isLandScape = orientation == 0 ? YES : NO;
  52. if (_landScape != isLandScape) {
  53. [self changeOrientation:isLandScape];
  54. }
  55. // 是否隐藏头部导航条
  56. self.hideTop = [parmDic boolValueForKey:@"isHideTitle"];
  57. }
  58. - (void)changeOrientation:(BOOL)isLandScape {
  59. self.landScape = isLandScape;
  60. if (isLandScape) {
  61. // 切换到横屏
  62. AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
  63. delegate.allowAutoRotate = YES;
  64. [UIDevice switchNewOrientation:UIInterfaceOrientationLandscapeRight];
  65. }
  66. else {
  67. AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
  68. delegate.allowAutoRotate = NO;
  69. [UIDevice switchNewOrientation:UIInterfaceOrientationPortrait];
  70. }
  71. }
  72. - (void)viewWillAppear:(BOOL)animated {
  73. [super viewWillAppear:animated];
  74. if (_hasChangeSource) {
  75. [self setParmDic:self.parmDic];
  76. }
  77. }
  78. - (void)viewWillDisappear:(BOOL)animated {
  79. [super viewWillDisappear:animated];
  80. if (_hasChangeSource && self.keepOrientation == NO && self.landScape == YES) {
  81. [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
  82. [self changeOrientation:NO];
  83. }
  84. self.keepOrientation = NO;
  85. }
  86. - (void)initWebView {
  87. [self.view addSubview:self.navView];
  88. CGFloat topHeight = kNaviBarHeight;
  89. if (self.hideTop) {
  90. topHeight = 0.0f;
  91. }
  92. [self.navView mas_makeConstraints:^(MASConstraintMaker *make) {
  93. make.left.right.top.mas_equalTo(self.view);
  94. make.height.mas_equalTo(topHeight);
  95. }];
  96. [self.view addSubview:self.webBackButton];
  97. [self.webBackButton mas_makeConstraints:^(MASConstraintMaker *make) {
  98. make.left.top.mas_equalTo(self.view);
  99. make.height.mas_equalTo(kNaviBarHeight);
  100. make.width.mas_equalTo(44);
  101. }];
  102. if (self.hideTop) {
  103. self.webBackButton.hidden = YES;
  104. }
  105. if (_hiddenNavBar) {
  106. topHeight = 0.0f;
  107. }
  108. if (self.headTitle) {
  109. [self.navView.topTitleLabel setText:_headTitle];
  110. }
  111. if (_myWebView == nil) {
  112. WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  113. config.selectionGranularity = WKSelectionGranularityDynamic;
  114. config.allowsInlineMediaPlayback = YES;
  115. if (@available(iOS 10.0, *)) {
  116. config.mediaTypesRequiringUserActionForPlayback = NO;
  117. } else {
  118. // Fallback on earlier versions
  119. config.requiresUserActionForMediaPlayback = NO;
  120. }
  121. config.processPool = [KSBaseWKWebViewController singleWkProcessPool];
  122. config.websiteDataStore = [WKWebsiteDataStore defaultDataStore];
  123. //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
  124. WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
  125. //这个类主要用来做native与JavaScript的交互管理
  126. WKUserContentController * wkUController = [[WKUserContentController alloc] init];
  127. [wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"COLEXIU"];
  128. config.userContentController = wkUController;
  129. WKPreferences *preferences = [WKPreferences new];
  130. // 是否支出javaScript
  131. preferences.javaScriptEnabled = YES;
  132. //不通过用户交互,是否可以打开窗口
  133. preferences.javaScriptCanOpenWindowsAutomatically = YES;
  134. config.preferences = preferences;
  135. _myWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];
  136. _myWebView.UIDelegate = self;
  137. _myWebView.navigationDelegate = self;
  138. _myWebView.scrollView.bounces = NO;
  139. _myWebView.scrollView.showsVerticalScrollIndicator = NO;
  140. _myWebView.scrollView.showsHorizontalScrollIndicator = NO;
  141. // 加载进度条和title
  142. [_myWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
  143. [_myWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
  144. [self.view addSubview:_myWebView];
  145. [_myWebView mas_makeConstraints:^(MASConstraintMaker *make) {
  146. make.left.right.mas_equalTo(self.view);
  147. make.top.mas_equalTo(self.view.mas_top).offset(topHeight);
  148. make.bottom.mas_equalTo(self.view.mas_bottom).offset(-iPhoneXSafeBottomMargin);
  149. }];
  150. if (@available(iOS 11.0, *)) {
  151. _myWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  152. } else {
  153. // Fallback on earlier versions
  154. }
  155. [self setupProgress];
  156. // 修改userAgent
  157. [self setUserAgent];
  158. [self.view bringSubviewToFront:self.navView];
  159. [self.view bringSubviewToFront:self.webBackButton];
  160. }
  161. else {
  162. [_myWebView reload];
  163. }
  164. }
  165. - (void)setUserAgent {
  166. MJWeakSelf;
  167. [self.myWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
  168. NSString *oldUserAgent = result;
  169. NSString *newUserAgent = [NSString stringWithFormat:@"%@ %@",oldUserAgent,@"COLEXIUAPPI"];
  170. weakSelf.myWebView.customUserAgent = newUserAgent;
  171. [weakSelf loadRequest];;
  172. }];
  173. }
  174. - (void)loadRequest {
  175. MJWeakSelf;
  176. [self.myWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
  177. NSLog(@"%@",result);
  178. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:weakSelf.url] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0f];
  179. [weakSelf.myWebView loadRequest:request];
  180. }];
  181. }
  182. - (NSString *)url {
  183. if (_url) {
  184. // if ([_url containsString:hostURL]) {
  185. if ([_url containsString:@"Authorization="]) {
  186. NSRange range = [_url rangeOfString:@"Authorization="];
  187. if (range.location != NSNotFound) {
  188. _url = [_url substringToIndex:range.location-1];
  189. }
  190. }
  191. NSString *sepectString = [_url containsString:@"?"] ? @"&" : @"?";
  192. NSString *tokenStr = UserDefault(TokenKey);
  193. if (![NSString isEmptyString:tokenStr]) {
  194. NSString *token = [[NSString stringWithFormat:@"Authorization=%@ %@", UserDefault(Token_type), tokenStr] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
  195. _url = [NSString stringWithFormat:@"%@%@%@",_url, sepectString, token];
  196. }
  197. // }
  198. }
  199. return _url;
  200. }
  201. #pragma mark --- 返回按钮的处理
  202. - (void)backAction {
  203. [self.myWebView stopLoading];
  204. if (_backRootView) {
  205. [self.navigationController popToRootViewControllerAnimated:NO];
  206. return;
  207. }
  208. else if (_isBackPreView) {
  209. [self.navigationController popViewControllerAnimated:YES];
  210. return;
  211. }
  212. else if ([self.myWebView canGoBack]) {
  213. [self.myWebView goBack];
  214. }
  215. else {
  216. [self.navigationController popViewControllerAnimated:YES];
  217. }
  218. }
  219. #pragma mark - WKScriptMessageHandler
  220. - (void)userContentController:(WKUserContentController *)userContentController
  221. didReceiveScriptMessage:(WKScriptMessage *)message {
  222. if ([message.name isEqualToString:@"COLEXIU"]) {
  223. NSDictionary *parm = [self convertJsonStringToNSDictionary:message.body];
  224. // 回到主线程
  225. dispatch_async(dispatch_get_main_queue(), ^{
  226. [self handleScriptMessageSource:parm];
  227. });
  228. }
  229. }
  230. - (void)handleScriptMessageSource:(NSDictionary *)parm {
  231. if ([[parm stringValueForKey:@"api"] isEqualToString:@"back"]) { // 返回
  232. [self.navigationController popViewControllerAnimated:YES];
  233. }
  234. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"login"]) {
  235. // 回到登录页面
  236. [self backLoginView];
  237. }
  238. // chat
  239. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"openConversationActivity"]) {
  240. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  241. NSString *name = [valueDic stringValueForKey:@"name"];
  242. NSString *userId = [NSString stringWithFormat:@"%.0f",[valueDic floatValueForKey:@"userId"]];
  243. KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] initWithConversationType:ConversationType_PRIVATE targetId:[NSString returnNoNullStringWithString:userId]];
  244. conversationVC.title = [NSString returnNoNullStringWithString:name];
  245. [self.navigationController pushViewController:conversationVC animated:YES];
  246. }
  247. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"openWebView"]) { // 打开新页面
  248. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  249. KSBaseWKWebViewController *detailCtrl = [[KSBaseWKWebViewController alloc] init];
  250. detailCtrl.url = [valueDic stringValueForKey:@"url"];
  251. detailCtrl.parmDic = valueDic;
  252. NSInteger orientation = [valueDic integerValueForKey:@"orientation"];
  253. BOOL isLandScape = orientation == 0 ? YES : NO;
  254. if (isLandScape == self.landScape) {
  255. self.keepOrientation = YES;
  256. detailCtrl.keepOrientation = YES;
  257. }
  258. [self postMessage:parm];
  259. [self.navigationController pushViewController:detailCtrl animated:YES];
  260. }
  261. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"setRequestedOrientation"]) {
  262. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  263. // 横竖屏
  264. NSInteger orientation = [valueDic integerValueForKey:@"orientation"];
  265. BOOL isLandScape = orientation == 0 ? YES : NO;
  266. [self changeOrientation:isLandScape];
  267. }
  268. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"keepScreenLongLight"]) {
  269. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  270. BOOL isOpenLight = [valueDic boolValueForKey:@"isOpenLight"];
  271. [[UIApplication sharedApplication] setIdleTimerDisabled:isOpenLight];
  272. }
  273. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"downLoad"]) {
  274. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  275. if ([valueDic stringValueForKey:@"PDF"]) {
  276. NSString *url = [valueDic stringValueForKey:@"downloadUrl"];
  277. [KSNetworkingManager downloadFileRequestWithFileUrl:url progress:^(int64_t bytesRead, int64_t totalBytes) {
  278. } success:^(NSURL * _Nonnull fileUrl) {
  279. MJWeakSelf;
  280. [self KSShowMsg:@"下载成功" promptCompletion:^{
  281. [weakSelf displaySource:fileUrl];
  282. }];
  283. } faliure:^(NSError * _Nonnull error) {
  284. }];
  285. }
  286. }
  287. // 回调是否刘海屏
  288. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"isSpecialShapedScreen"]) {
  289. BOOL isShapedScreen = iPhoneXSafeTopMargin > 0 ? YES : NO;
  290. NSMutableDictionary *valueDic = [NSMutableDictionary dictionaryWithDictionary:[parm dictionaryValueForKey:@"content"]];
  291. [valueDic setValue:@(isShapedScreen) forKey:@"isSpecialShapedScreen"];
  292. [valueDic setValue:@(iPhoneXSafeTopMargin*2) forKey:@"notchHeight"];
  293. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  294. [sendParm setValue:valueDic forKey:@"content"];
  295. [self postMessage:sendParm];
  296. }
  297. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"getToken"]) {
  298. NSMutableDictionary *valueDic = [NSMutableDictionary dictionaryWithDictionary:[parm dictionaryValueForKey:@"content"]];
  299. [valueDic setValue:UserDefault(Token_type) forKey:@"tokenType"];
  300. [valueDic setValue:UserDefault(TokenKey) forKey:@"accessToken"];
  301. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  302. [sendParm setValue:valueDic forKey:@"content"];
  303. [self postMessage:sendParm];
  304. }
  305. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"openAccompanyWebView"]) { // 打开伴奏
  306. PREMISSIONTYPE micEnable = [RecordCheckManager checkPermissionShowAlert:NO showInView:nil];
  307. PREMISSIONTYPE cameraEnable = [RecordCheckManager checkCameraPremissionAvaiable:NO showInView:nil];
  308. if (micEnable == PREMISSIONTYPE_YES && cameraEnable == PREMISSIONTYPE_YES) { // 如果麦克风和摄像头权限都有
  309. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  310. KSAccompanyWebViewController *detailCtrl = [[KSAccompanyWebViewController alloc] init];
  311. detailCtrl.url = [valueDic stringValueForKey:@"url"];
  312. detailCtrl.parmDic = valueDic;
  313. detailCtrl.hiddenNavBar = [valueDic boolValueForKey:@"isHideTitle"];
  314. NSInteger orientation = [valueDic integerValueForKey:@"orientation"];
  315. BOOL isLandScape = orientation == 0 ? YES : NO;
  316. if (isLandScape == self.landScape) {
  317. self.keepOrientation = YES;
  318. detailCtrl.keepOrientation = YES;
  319. }
  320. [self postMessage:parm];
  321. [self.navigationController pushViewController:detailCtrl animated:YES];
  322. }
  323. else {
  324. if (micEnable == PREMISSIONTYPE_NO && cameraEnable == PREMISSIONTYPE_NO) { // 如果麦克风权限和摄像头权限都没有
  325. [self showAlertWithMessage:@"请开启相机和麦克风访问权限" type:CHECKDEVICETYPE_BOTH];
  326. }
  327. else if (micEnable == PREMISSIONTYPE_NO) { // 如果没有麦克风权限
  328. [self showAlertWithMessage:@"请开启麦克风访问权限" type:CHECKDEVICETYPE_MIC];
  329. }
  330. else if (cameraEnable == PREMISSIONTYPE_NO) { // 如果没有摄像头权限
  331. [self showAlertWithMessage:@"请开启相机访问权限" type:CHECKDEVICETYPE_CAMREA];
  332. }
  333. }
  334. }
  335. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"checkAlbum"]) { // 判断权限
  336. [self postMessage:parm];
  337. PREMISSIONTYPE albumEnable = [RecordCheckManager checkPhotoLibraryPremissionAvaiable:NO showInView:nil];
  338. if (albumEnable == PREMISSIONTYPE_NO) {
  339. [self showAlertWithMessage:@"请开启相册访问权限" type:CHECKDEVICETYPE_CAMREA];
  340. }
  341. }
  342. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"shareAchievements"]) { // 分享
  343. //
  344. [self shareFunctionWithParm:parm];
  345. }
  346. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"getNavHeight"]) { // 获取状态栏高度和 title heigt
  347. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  348. [valueDic setValue:[NSNumber numberWithFloat:STATUS_GAP*2] forKey:@"navHeight"];
  349. [valueDic setValue:@(44*2) forKey:@"titleHeight"];
  350. [parm setValue:valueDic forKey:@"content"];
  351. [self postMessage:parm];
  352. }
  353. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"backIconChange"]) {
  354. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  355. NSString *backColor = [valueDic stringValueForKey:@"iconStyle"];
  356. NSString *backImage = @"";
  357. if ([backColor isEqualToString:@"black"]) {
  358. backImage = @"back_black";
  359. }
  360. else {
  361. backImage = @"back_button_white";
  362. }
  363. [self.webBackButton.backButton setImage:[UIImage imageNamed:backImage] forState:UIControlStateNormal];
  364. }
  365. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"setBarStatus"]) { // 顶部是否隐藏
  366. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  367. BOOL isShow = [valueDic boolValueForKey:@"status"]; // 0 隐藏 1 显示
  368. self.hiddenNavBar = !isShow;
  369. CGFloat navHeight = isShow ? kNaviBarHeight : 0;
  370. [self.navView mas_updateConstraints:^(MASConstraintMaker *make) {
  371. make.height.mas_equalTo(navHeight);
  372. }];
  373. [self.myWebView mas_updateConstraints:^(MASConstraintMaker *make) {
  374. make.top.mas_equalTo(self.view.mas_top).offset(navHeight);
  375. }];
  376. }
  377. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"paymentOrder"]) {
  378. NSDictionary *content = [parm dictionaryValueForKey:@"content"];
  379. NSString *channel = [content stringValueForKey:@"payChannel"];
  380. if ([channel isEqualToString:@"alipay"]) {
  381. NSString *infoMessage = [content stringValueForKey:@"payInfo"];
  382. [KSOrderManager dealWithAliSDK:infoMessage];
  383. }
  384. else if ([channel isEqualToString:@"wx_lite"]) {
  385. }
  386. // [KSOrderManager dealWithAliOrder:infoMessage];
  387. }
  388. else if ([[parm stringValueForKey:@"api"] isEqualToString:@"joinChatGroup"]) {
  389. NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  390. NSString *targetId = [valueDic stringValueForKey:@"id"];
  391. if ([valueDic stringValueForKey:@"single"]) { // 单聊
  392. KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
  393. ctrl.targetId = targetId;
  394. ctrl.conversationType = ConversationType_PRIVATE;
  395. [self.navigationController pushViewController:ctrl animated:YES];
  396. }
  397. else if ([valueDic stringValueForKey:@"multi"]) { // 群聊
  398. KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
  399. ctrl.targetId = targetId;
  400. ctrl.conversationType = ConversationType_GROUP;
  401. [self.navigationController pushViewController:ctrl animated:YES];
  402. }
  403. }
  404. // else if ([[parm stringValueForKey:@"api"] isEqualToString:@"enterLiveRoom"]) { // 进入直播间
  405. // NSDictionary *valueDic = [parm dictionaryValueForKey:@"content"];
  406. // NSString *roomId = [valueDic stringValueForKey:@"roomId"];
  407. // [KSEnterLiveroomManager joinLiveWithRoomId:roomId inController:(CustomNavViewController *)self.navigationController];
  408. // }
  409. }
  410. - (UIImage *)imageWithBase64String:(NSString *)base64String {
  411. NSURL *URL = [NSURL URLWithString:base64String];
  412. NSData *imageData = [NSData dataWithContentsOfURL:URL];
  413. UIImage *image = [UIImage imageWithData:imageData scale:2];
  414. return image;
  415. }
  416. - (void)shareFunctionWithParm:(NSDictionary *)parm {
  417. // NSDictionary *content = [parm dictionaryValueForKey:@"content"];
  418. // NSString *typeString = [content stringValueForKey:@"type"];
  419. // KSSHARETYPE shareType = [typeString isEqualToString:@"image"] ? KSSHARETYPE_IMAGE : KSSHARETYPE_VODEO;
  420. // NSString *shareTitle = [content stringValueForKey:@"title"];
  421. // NSString *descMessage = [content stringValueForKey:@"desc"];
  422. // NSString *videoUrl = [content stringValueForKey:@"video"];
  423. // NSString *imgStr = [content stringValueForKey:@"image"];
  424. // UIImage *shareImage = [self imageWithBase64String:imgStr];
  425. // [KSUMShareManager shareInstanceWithImage:shareImage url:videoUrl shareTitle:shareTitle descMessage:descMessage shareType:shareType showInView:self callback:^(BOOL isSuccess, NSString *descMessage) {
  426. // NSMutableDictionary *responParm = [NSMutableDictionary dictionary];
  427. // [responParm setValue:[parm stringValueForKey:@"api"] forKey:@"api"];
  428. // NSMutableDictionary *content = [NSMutableDictionary dictionary];
  429. // [content setValue:[content stringValueForKey:@"UUID"] forKey:@"content"];
  430. // [content setValue:descMessage forKey:@"message"];
  431. // BOOL status = isSuccess;
  432. // [content setValue:[NSNumber numberWithBool:status] forKey:@"status"];
  433. // [responParm setValue:content forKey:@"content"];
  434. // [self postMessage:responParm];
  435. // }];
  436. }
  437. - (void)showAlertWithMessage:(NSString *)message type:(CHECKDEVICETYPE)deviceType {
  438. [KSPremissionAlert shareInstanceDisplayImage:deviceType message:message showInView:self.view cancel:^{
  439. } confirm:^{
  440. [self openSettingView];
  441. }];
  442. }
  443. - (void)openSettingView {
  444. if (@available(iOS 10, *)) {
  445. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
  446. } else {
  447. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  448. }
  449. }
  450. - (void)displaySource:(NSURL *)localUrl {
  451. KSLocalWebViewController *ctrl = [[KSLocalWebViewController alloc] init];
  452. ctrl.headTitle = @"协议文件";
  453. ctrl.sourceData = [NSData dataWithContentsOfURL:localUrl];
  454. ctrl.fileUrl = localUrl;
  455. [self.navigationController pushViewController:ctrl animated:YES];
  456. }
  457. - (void)postMessage:(NSDictionary *)parm {
  458. if (_myWebView) {
  459. dispatch_async(dispatch_get_main_queue(), ^{
  460. NSString *jsString = [parm mj_JSONString];
  461. [self.myWebView evaluateJavaScript:[NSString stringWithFormat:@"postMessage(%@,'*')", jsString] completionHandler:nil];
  462. });
  463. }
  464. }
  465. // 刷新
  466. - (void)refreshUrl:(NSString *)refreshUrl {
  467. NSString *sepectString = [refreshUrl containsString:@"?"] ? @"&" : @"?";
  468. NSString *tokenStr = UserDefault(TokenKey);
  469. if (![NSString isEmptyString:tokenStr]) {
  470. NSString *token = [[NSString stringWithFormat:@"Authorization=%@ %@", UserDefault(Token_type), tokenStr] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
  471. refreshUrl = [NSString stringWithFormat:@"%@%@%@",refreshUrl, sepectString, token];
  472. }
  473. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:refreshUrl] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0f];
  474. [self.myWebView loadRequest:request];
  475. }
  476. // 返回登录页面
  477. - (void)backLoginView {
  478. [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
  479. [RCConnectionManager shareManager].isNeedJoin = NO;
  480. [RCConnectionManager shareManager].isNeedShowMessage = NO;
  481. [[RCIM sharedRCIM] logout];
  482. NSString *webUrl = [self.url copy];
  483. if ([webUrl containsString:@"Authorization="]) {
  484. NSRange range = [webUrl rangeOfString:@"Authorization="];
  485. if (range.location != NSNotFound) {
  486. webUrl = [webUrl substringToIndex:range.location-1];
  487. }
  488. }
  489. // 获取次数
  490. NSString *failCount = UserDefault(@"WEB_FAILCOUNT");
  491. if ([NSString isEmptyString:failCount]) {
  492. failCount = @"1";
  493. UserDefaultSetObjectForKey(failCount, @"WEB_FAILCOUNT");
  494. UserDefaultSetObjectForKey(webUrl, WEB_URL);
  495. }
  496. else if (failCount.integerValue == 1) {
  497. NSString *preUrl = UserDefaultObjectForKey(FAIL_WEB_URL);
  498. if (![webUrl isEqualToString:preUrl]) { // 如果打开和之前失败不相同重新统计数据
  499. UserDefaultSetObjectForKey(@"1", @"WEB_FAILCOUNT");
  500. UserDefaultSetObjectForKey(webUrl, WEB_URL);
  501. }
  502. else {
  503. UserDefaultRemoveObjectForKey(@"WEB_FAILCOUNT");
  504. }
  505. }
  506. else {
  507. UserDefaultRemoveObjectForKey(@"WEB_FAILCOUNT");
  508. }
  509. // 当前失败的H5地址
  510. UserDefaultSetObjectForKey(webUrl, FAIL_WEB_URL);
  511. // 取消推送别名
  512. [JPUSHService deleteAlias:nil seq:0];
  513. [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
  514. [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
  515. [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
  516. [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
  517. [KSNetworkingManager clearRequestHeader];
  518. LoginViewController *loginVC = [[LoginViewController alloc] init];
  519. CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
  520. AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
  521. appDelegate.window.rootViewController = navCtrl;
  522. }
  523. #pragma mark ----- WKWebView delegate
  524. // 1 在发送请求之前,决定是否跳转
  525. - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
  526. NSLog(@"1-------在发送请求之前,决定是否跳转 -->%@",navigationAction.request);
  527. NSURL *url = navigationAction.request.URL;
  528. NSString *scheme = [url scheme];
  529. UIApplication *app = [UIApplication sharedApplication];
  530. NSString *urlString = url.absoluteString;
  531. if (![urlString containsString:@"colexiu.com"] && ![urlString containsString:WEBHOST]) { // 外部链接
  532. self.isOutLink = YES;
  533. }
  534. else {
  535. self.isOutLink = NO;
  536. }
  537. // 打电话
  538. if ([scheme isEqualToString:@"tel"]) {
  539. if ([app canOpenURL:url]) {
  540. [app openURL:url];
  541. // 一定要加上这句,否则会打开新页面
  542. decisionHandler(WKNavigationActionPolicyCancel);
  543. return;
  544. }
  545. }
  546. decisionHandler(WKNavigationActionPolicyAllow);
  547. }
  548. // 2 页面开始加载时调用
  549. - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
  550. NSLog(@"2-------页面开始加载时调用");
  551. }
  552. // 3 在收到响应后,决定是否跳转
  553. - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
  554. /// 在收到服务器的响应头,根据response相关信息,决定是否跳转。decisionHandler必须调用,来决定是否跳转,参数WKNavigationActionPolicyCancel取消跳转,WKNavigationActionPolicyAllow允许跳转
  555. NSLog(@"3-------在收到响应后,决定是否跳转");
  556. decisionHandler(WKNavigationResponsePolicyAllow);
  557. }
  558. // 4 当内容开始返回时调用
  559. - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
  560. NSLog(@"4-------当内容开始返回时调用");
  561. }
  562. // 5 页面加载完成之后调用
  563. - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
  564. NSLog(@"5-------页面加载完成之后调用");
  565. if (_hasModify == NO) {
  566. [self configLocalStorage];
  567. }
  568. }
  569. // 调用js方法
  570. - (void)postMessageJS:(NSDictionary *)jsDict {
  571. NSString *jsString = [jsDict mj_JSONString];
  572. [self.myWebView evaluateJavaScript:[NSString stringWithFormat:@"sendMessage(%@)", jsString] completionHandler:nil];
  573. }
  574. // 6 页面加载失败时调用
  575. - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation {
  576. NSLog(@"6-------页面加载失败时调用");
  577. }
  578. // 接收到服务器跳转请求之后调用
  579. - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
  580. NSLog(@"-------接收到服务器跳转请求之后调用");
  581. }
  582. // 数据加载发生错误时调用
  583. - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
  584. NSLog(@"----数据加载发生错误时调用");
  585. }
  586. - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *_Nullable))completionHandler
  587. {
  588. if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  589. if (challenge.previousFailureCount == 0) {
  590. NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
  591. completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
  592. } else {
  593. completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
  594. }
  595. }
  596. }
  597. //当因为某些问题,导致webView进程终止时触发
  598. - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
  599. NSLog(@"%s", __func__);
  600. [webView reload];
  601. }
  602. /**
  603. * web界面中有弹出警告框时调用
  604. *
  605. * @param webView 实现该代理的webview
  606. * @param message 警告框中的内容
  607. * @param completionHandler 警告框消失调用
  608. */
  609. - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
  610. NSLog(@"-------web界面中有弹出警告框时调用");
  611. NSLog(@"%@",message);
  612. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
  613. message:nil
  614. preferredStyle:UIAlertControllerStyleAlert];
  615. [alertController addAction:[UIAlertAction actionWithTitle:@"确定"
  616. style:UIAlertActionStyleCancel
  617. handler:^(UIAlertAction *action) {
  618. completionHandler();
  619. }]];
  620. [self presentViewController:alertController animated:YES completion:nil];
  621. }
  622. // 取消和确认的按钮
  623. - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
  624. // js 里面的alert实现,如果不实现,网页的alert函数无效 ,
  625. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
  626. message:nil
  627. preferredStyle:UIAlertControllerStyleAlert];
  628. [alertController addAction:[UIAlertAction actionWithTitle:@"确定"
  629. style:UIAlertActionStyleDefault
  630. handler:^(UIAlertAction *action) {
  631. completionHandler(YES);
  632. }]];
  633. [alertController addAction:[UIAlertAction actionWithTitle:@"取消"
  634. style:UIAlertActionStyleCancel
  635. handler:^(UIAlertAction *action){
  636. completionHandler(NO);
  637. }]];
  638. [self presentViewController:alertController animated:YES completion:^{}];
  639. }
  640. #pragma mark - KVO回馈
  641. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
  642. if ([keyPath isEqualToString:@"estimatedProgress"]) {
  643. self.progressLayer.opacity = 1;
  644. if ([change[@"new"] floatValue] <[change[@"old"] floatValue]) {
  645. return;
  646. }
  647. self.progressLayer.frame = CGRectMake(0, 0, kScreenWidth*[change[@"new"] floatValue], 3);
  648. if ([change[@"new"]floatValue] == 1.0) {
  649. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  650. self.progressLayer.opacity = 0;
  651. self.progressLayer.frame = CGRectMake(0, 0, 0, 3);
  652. });
  653. }
  654. }else if ([keyPath isEqualToString:@"title"]) {
  655. // 顶部title
  656. self.headTitle = change[@"new"];
  657. if (self.hiddenNavBar == NO) {
  658. self.navView.topTitleLabel.text = self.headTitle;
  659. }
  660. }
  661. }
  662. /*
  663. #pragma mark - Navigation
  664. // In a storyboard-based application, you will often want to do a little preparation before navigation
  665. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  666. // Get the new view controller using [segue destinationViewController].
  667. // Pass the selected object to the new view controller.
  668. }
  669. */
  670. - (void)configLocalStorage {
  671. _hasModify = YES;
  672. if (![NSString isEmptyString:UserDefault(TokenKey)]) {
  673. NSString *jsString = [NSString stringWithFormat:@"localStorage.setItem('Authorization', '%@ %@')",UserDefault(Token_type), UserDefault(TokenKey)];
  674. [self.myWebView evaluateJavaScript:jsString completionHandler:nil];
  675. }
  676. }
  677. - (void)setupProgress {
  678. UIView *progress = [[UIView alloc]init];
  679. progress.frame = CGRectMake(0, 0, kScreenWidth, 3);
  680. progress.backgroundColor = [UIColor clearColor];
  681. [self.view addSubview:progress];
  682. CALayer *layer = [CALayer layer];
  683. layer.frame = CGRectMake(0, 0, 0, 3);
  684. layer.backgroundColor = THEMECOLOR.CGColor;
  685. [progress.layer addSublayer:layer];
  686. self.progressLayer = layer;
  687. }
  688. + (WKProcessPool*)singleWkProcessPool {
  689. static WKProcessPool *sharedPool;
  690. static dispatch_once_t onceToken;
  691. dispatch_once(&onceToken, ^{
  692. sharedPool = [[WKProcessPool alloc] init];
  693. });
  694. return sharedPool;
  695. }
  696. - (NSDictionary *)convertJsonStringToNSDictionary:(NSString *)jsonString {
  697. if (jsonString == nil) {
  698. return nil;
  699. }
  700. NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
  701. NSError *error;
  702. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
  703. if (error) {
  704. NSLog(@"jsonString解析失败:%@", error);
  705. return nil;
  706. }
  707. return json;
  708. }
  709. - (void)setHiddenNavBar:(BOOL)hiddenNavBar {
  710. _hiddenNavBar = hiddenNavBar;
  711. if (hiddenNavBar) {
  712. self.navView.topTitleLabel.text = @"";
  713. }
  714. else {
  715. self.navView.topTitleLabel.text = self.headTitle;
  716. }
  717. }
  718. #pragma mark --- lazying
  719. - (KSWebNavView *)navView {
  720. if (!_navView) {
  721. _navView = [[KSWebNavView alloc] init];
  722. }
  723. return _navView;
  724. }
  725. - (KSWebBackButton *)webBackButton {
  726. if (!_webBackButton) {
  727. _webBackButton = [[KSWebBackButton alloc] init];
  728. MJWeakSelf;
  729. [_webBackButton webViewBackAction:^{
  730. [weakSelf backAction];
  731. }];
  732. }
  733. return _webBackButton;
  734. }
  735. - (void)dealloc {
  736. [[_myWebView configuration].userContentController removeScriptMessageHandlerForName:@"COLEXIU"];
  737. [_myWebView removeObserver:self forKeyPath:@"estimatedProgress"];
  738. [_myWebView removeObserver:self forKeyPath:@"title"];
  739. [_myWebView loadHTMLString:@"" baseURL:nil];
  740. [_myWebView removeFromSuperview];
  741. _myWebView = nil;
  742. [[NSURLCache sharedURLCache] removeAllCachedResponses];
  743. [[NSURLCache sharedURLCache] setDiskCapacity:0];
  744. [[NSURLCache sharedURLCache] setMemoryCapacity:0];
  745. [[NSNotificationCenter defaultCenter] removeObserver:self];
  746. }
  747. - (NSString *)getSaveSpeedPath {
  748. // 在Documents目录下创建一个名为AudioSpeedFile的文件夹
  749. NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioSpeedFile"];
  750. NSLog(@"%@",path);
  751. NSFileManager *fileManager = [NSFileManager defaultManager];
  752. BOOL isDir = FALSE;
  753. BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
  754. if(!(isDirExist && isDir)) {
  755. BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
  756. if(!bCreateDir){
  757. NSLog(@"创建文件夹失败!");
  758. }
  759. NSLog(@"创建文件夹成功,文件路径%@",path);
  760. }
  761. path = [path stringByAppendingPathComponent:@"songSpeed.plist"];
  762. NSLog(@"file path:%@",path);
  763. return path;
  764. }
  765. /*
  766. #pragma mark - Navigation
  767. // In a storyboard-based application, you will often want to do a little preparation before navigation
  768. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  769. // Get the new view controller using [segue destinationViewController].
  770. // Pass the selected object to the new view controller.
  771. }
  772. */
  773. @end