前提:在iOS控制器中加載UIWebView,設(shè)置代理,遵守UIWebViewDelegate協(xié)議廉羔。
一胀屿、iOS調(diào)用JS方法
通過iOS調(diào)用JS代碼實現(xiàn)起來比較方便直接調(diào)用UIWebView的方法- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
1.查詢標(biāo)簽
// 查詢標(biāo)簽
NSString *str = @"var word = document.getElementById('word');"
@"alert(word.innerHTML)";
[webView stringByEvaluatingJavaScriptFromString:str];
2.為網(wǎng)頁添加標(biāo)簽:
NSString *str = @"var img = document.createElement('img');"
"img.src = 'icon5.jpg';"
"img.width = 300;"
"img.heigth = 100;"
"document.body.appendChild(img);";
[webView stringByEvaluatingJavaScriptFromString:str];
3.刪除網(wǎng)頁標(biāo)簽:
// 刪除標(biāo)簽
NSString *str1 = @"var word = document.getElementById('word');"
@"word.remove();";
[webView stringByEvaluatingJavaScriptFromString:str1];
4.更改標(biāo)簽:
// 更改
NSString *str2 = @"var change = document.getElementsByClassName('change')[0];"
"change.innerHTML = 'hello';";
NSString *result =? [webView stringByEvaluatingJavaScriptFromString:str2];
HTML端代碼:
iOS和H5交互
6666666666
111111
222222
333333
444444
提交信息
alert('這個一個彈框');
二塘揣、JS調(diào)用iOS方法:
1.第一種方法比較簡單,通過字符串的比對宿崭。這種方式iOS端代碼比較簡單亲铡,網(wǎng)頁加載完成后后臺需要重新定義網(wǎng)頁url,將移動端需要的參數(shù)拼接到url上返回,或者按照和后臺約定好的字段來進行字符串比對以達到調(diào)用iOS方法的目的奖蔓。下面貼代碼赞草。
oc代碼:(需要實現(xiàn)webView的協(xié)議)
// 攔截協(xié)議頭,調(diào)取系統(tǒng)攝像頭
#pragma mark UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:??????????? (UIWebViewNavigationType)navigationType
{
NSString *str = request.URL.absoluteString;
if ([str containsString:@"wxd://"]) {
[self getImage];
}
return YES;
}
- (void)getImage
{
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { //調(diào)用相冊
//實例化控制器
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
// 是否有圖片選取框
picker.allowsEditing = YES;
[self presentViewController:picker animated:YES completion:nil];
}
}
HTML端代碼:
在html中調(diào)用oc的方法
訪問相冊
function getImage(){
window.location.href = "wxd://getImage";
}
2.第二種方法吆鹤,JS直接用oc方法名來調(diào)用oc方法厨疙,類似于安卓.addJavascriptInterface(new JsObject(), "Android")方法,頭文件需要導(dǎo)入#import 疑务。
首先創(chuàng)建一個繼承自NSObject的類沾凄,在這里我命名為JSTestObjext,.h代碼如下:
.m中實現(xiàn)協(xié)議方法知允,代碼如下:
之后在加載webView的控制器中調(diào)用:
到此為止撒蟀,oc代碼就已經(jīng)寫完了,我們只需告訴JS端使用testobject類廊镜,就可以調(diào)oc的方法了牙肝。下面附上JS調(diào)用的代碼:
*********
之前的博客寫過使用庫來實現(xiàn)與H5的交互,但是在項目中還是遇到了一些不得不踩的坑嗤朴。在這里將我遇到的問題以及參考網(wǎng)上幾位大神的解決方案列舉出來配椭,如果有更好的辦法,歡迎討論指正雹姊。在閱讀本博客前股缸,請參閱我之前的《iOS與H5交互》。
一吱雏、問題一:在webView中加載H5界面敦姻,webView中的H5一級界面可以輕松實現(xiàn)oc與js方法互調(diào),但如果在H5界面上進入二級界面歧杏,二級界面中再使用之前方法來交互就會失效镰惦。如圖:左圖為H5一級界面,右圖為二級界面犬绒。
解決辦法:
第一步:在控制器中聲明兩個變量旺入,isNotFirstLoad用來記錄webView是否是第一次加載網(wǎng)頁;loadCount計數(shù)器凯力,用來記錄網(wǎng)頁轉(zhuǎn)跳次數(shù)茵瘾,做返回處理。
第二步:實現(xiàn)- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType方法咐鹤,代碼如下:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// isNotFirstLoad,記錄webView是否第一次加載H5頁面
if (isNotFirstLoad) {
CGRect frame = self.webView.frame;
[self.webView removeFromSuperview];
[self.animationView removeFromSuperview];
UIWebView *webView = [[UIWebView alloc] initWithFrame:frame];
webView.delegate = self;
[self.view addSubview:webView];
[webView loadRequest:request];
self.webView = webView;
//首先創(chuàng)建JSContext 對象(此處通過當(dāng)前webView的鍵獲取到j(luò)scontext)
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//創(chuàng)建JSTestObjext對象拗秘,賦值給js的對象
JSTestObjext *test = [JSTestObjext new];
test.delegate = self;
context[@"iOS"] = test;
isNotFirstLoad = NO;
return NO;
}
isNotFirstLoad = YES;
// 計數(shù)器,用來記錄網(wǎng)頁轉(zhuǎn)跳次數(shù)祈惶,做返回處理
loadCount ++;
if (loadCount == 3) {
loadCount = 1;
}
return YES;
}
在網(wǎng)頁轉(zhuǎn)跳二級界面的時候重新創(chuàng)建UIWebView和JSContext對象雕旨,將其當(dāng)成一個新的網(wǎng)頁扮匠,再使用JSContext對象來實現(xiàn)交互的時候就不會出現(xiàn)失效的情況。
第三步:此時在H5二級界面互調(diào)方法就不會有問題了奸腺,但新的問題又出現(xiàn)了餐禁,當(dāng)點擊返回按鈕的時候如何返回上級界面。這時就要用到申明的loadCount成員變量了突照。具體代碼寫在自定義返回按鈕的點擊事件中,我在項目中導(dǎo)航欄是自定義的氧吐,重寫返回按鈕只需重寫導(dǎo)航欄的leftBarButtonItem讹蘑。代碼如下:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = self.webTitle;
// 設(shè)置導(dǎo)航欄返回按鈕
self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithIcon:@"nav_menu_back_02" highlighted:@"nav_menu_back_03" target:self action:@selector(backClick)];
[self createUI];
}
返回按鈕點擊事件代碼如下:
/**
*? 返回按鈕點擊事件
*/
- (void)backClick
{
if (loadCount == 1) { // pop到上級VC
[self.navigationController popViewControllerAnimated:YES];
}else{ // 如果計數(shù)器為2,重新加載一級界面的url
NSURL *url = [NSURL URLWithString:self.url];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
}
到此這個問題算是解決了。
二筑舅、問題二:當(dāng)H5界面中嵌套視頻座慰,在用手機橫屏播放視頻,點擊右上角完成按鈕退出播放界面的時候翠拣,會出現(xiàn)導(dǎo)航欄上移版仔,與狀態(tài)欄重合的bug。如圖:
左圖為正常進入H5界面的樣子误墓,點擊視頻播放按鈕蛮粮,進入視頻播放界面,打開手機的豎排方向鎖定谜慌,在手機橫屏?xí)r候播放器會自動橫屏播放然想,這時點擊播放起左上角完成按鈕活著右下角全屏按鈕退出播放界面就會出現(xiàn)右圖的bug,導(dǎo)航欄會向上移動欣范,與狀態(tài)欄重合变泄。
解決方法:
第一步:在AppDelegate.h中增加一個屬性值,用來設(shè)置是否允許橫屏恼琼。代碼如下:
#import
@interface AppDelegate : UIResponder
@property (strong, nonatomic) UIWindow *window;
/***? 是否允許橫屏的標(biāo)記 */
@property (nonatomic,assign)BOOL allowRotation;
@end
在AppDelegate.m中實現(xiàn)- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window方法妨蛹,具體代碼如下:
/**
*? 是否允許橫屏
*/
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window{
if (self.allowRotation) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
第二步:在加載webView的控制器中注冊兩個通知,通過監(jiān)聽UIWindow是否可見來判斷視頻播放器是否出現(xiàn)晴竞。在viewDidLoad中注冊通知蛙卤,見代碼:
// 播放視頻,監(jiān)聽視頻播放器
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(begainFullScreen) name:UIWindowDidBecomeVisibleNotification object:nil];//進入全屏
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endFullScreen) name:UIWindowDidBecomeHiddenNotification object:nil];//退出全屏
實現(xiàn)通知方法:
- (void)begainFullScreen
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.allowRotation = YES;
}
/**
*? 退出全屏
*/
- (void)endFullScreen
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.allowRotation = NO;
// 設(shè)置設(shè)備方向為豎排
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = UIInterfaceOrientationPortrait;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
獲取appDelegate需要引入頭文件#import "AppDelegate.h"颓鲜。這樣就可以避免導(dǎo)航欄上移出現(xiàn)的bug表窘。