之前的博客写过使用<JavaScriptCore/JavaScriptCore.h>库来实现与H5的交互,但是在项目中还是遇到了一些不得不踩的坑。在这里将我遇到的问题以及参考网上几位大神的解决方案列举出来,如果有更好的办法,欢迎讨论指正。在阅读本博客前,请参阅我之前的《iOS与H5交互》

关于下面问题一,将JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]放到webViewDidFinishLoad方法中可避免出现类似的bug。这里感谢 @有棱角的圆 同学的热情指正,关于这部分的具体代码请移步http://www.cnblogs.com/sunjianfei/p/6559396.html

一、问题一:在webView中加载H5界面,webView中的H5一级界面可以轻松实现oc与js方法互调,但如果在H5界面上进入二级界面,二级界面中再使用之前方法来交互就会失效。如图:左图为H5一级界面,右图为二级界面。

   

解决办法:

第一步:在控制器中声明两个变量,isNotFirstLoad用来记录webView是否是第一次加载网页;loadCount计数器,用来记录网页转跳次数,做返回处理。

第二步:实现- (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;
        
        //首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
        JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        //创建JSTestObjext对象,赋值给js的对象
        JSTestObjext *test = [JSTestObjext new];
        test.delegate = self;
        context[@"iOS"] = test;
        
        isNotFirstLoad = NO;
        return NO;
    }
    isNotFirstLoad = YES;
    
    // 计数器,用来记录网页转跳次数,做返回处理
    loadCount ++;
    if (loadCount == 3) {
        loadCount = 1;
    }
    return YES;
}
在网页转跳二级界面的时候重新创建UIWebView和JSContext对象,将其当成一个新的网页,再使用JSContext对象来实现交互的时候就不会出现失效的情况。

第三步:此时在H5二级界面互调方法就不会有问题了,但新的问题又出现了,当点击返回按钮的时候如何返回上级界面。这时就要用到申明的loadCount成员变量了。具体代码写在自定义返回按钮的点击事件中,我在项目中导航栏是自定义的,重写返回按钮只需重写导航栏的leftBarButtonItem。代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = self.webTitle;
    
    // 设置导航栏返回按钮
    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{ // 如果计数器为2,重新加载一级界面的url
        NSURL *url = [NSURL URLWithString:self.url];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [self.webView loadRequest:request];
    }
}

到此这个问题算是解决了。

二、问题二:当H5界面中嵌套视频,在用手机横屏播放视频,点击右上角完成按钮退出播放界面的时候,会出现导航栏上移,与状态栏重合的bug。如图:

左图为正常进入H5界面的样子,点击视频播放按钮,进入视频播放界面,打开手机的竖排方向锁定,在手机横屏时候播放器会自动横屏播放,这时点击播放起左上角完成按钮活着右下角全屏按钮退出播放界面就会出现右图的bug,导航栏会向上移动,与状态栏重合。

解决方法:

第一步:在AppDelegate.h中增加一个属性值,用来设置是否允许横屏。代码如下:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

/***  是否允许横屏的标记 */
@property (nonatomic,assign)BOOL allowRotation;

@end

在AppDelegate.m中实现- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window方法,具体代码如下:

/**
 *  是否允许横屏
 */
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window{
    if (self.allowRotation) {
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

第二步:在加载webView的控制器中注册两个通知,通过监听UIWindow是否可见来判断视频播放器是否出现。在viewDidLoad中注册通知,见代码:

// 播放视频,监听视频播放器
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(begainFullScreen) name:UIWindowDidBecomeVisibleNotification object:nil];//进入全屏
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endFullScreen) name:UIWindowDidBecomeHiddenNotification object:nil];//退出全屏

实现通知方法:

- (void)begainFullScreen
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    appDelegate.allowRotation = YES;
}

/**
 *  退出全屏
 */
- (void)endFullScreen
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    appDelegate.allowRotation = NO;
    // 设置设备方向为竖排
    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"。这样就可以避免导航栏上移出现的bug。

iOS与H5交互遇到的坑的更多相关文章

  1. iOS与H5交互

    H5与App原生交互,一般会是前端页面中的JavaScript与App使用的原生开发语言的交互.技术方案应能达到以下要求: 在js与原生进行交互的时候能保证正常的正向调用逻辑返回,反向可以处理异步回调 ...

  2. WebViewJavascriptBridge详细使用 iOS与H5交互的方案

    WebViewJavascriptBridge详细使用 源网址: https://www.cnblogs.com/jiang-xiao-yan/p/5345755.html    前言 WebView ...

  3. IOS与h5交互记录

    博主之前做过移动端app嵌入网页,与Android和IOS有交互,一直没有时间分享过程.这里不多说Android交互啦-很简单,详细了解IOS与h5的交互吧. IOS不同语法和h5的交互所建立的JSB ...

  4. iOS与H5交互及UIWebView缓存

    iOS原生App与H5页面交互笔记 最近在做一个项目用到了原生App与H5交互,之前有做过简单的H5页面直接调用原生方法的例子,就是利用UIWebView中的代理方法 //webview每次加载之前都 ...

  5. iOS与H5交互(WKWbebView)

    前言: 在iOS开发中,或多或少的会嵌入一些H5页面,有时候需要原生代码和H5页面进行交互.iOS8开始苹果推出性能更强大的WKWebView,所以一下方法是关于WKWebView与JS的交互. 创建 ...

  6. app中h5交互的一些坑 记录笔记

    1.ios开发镶嵌 h5页面 存在input 圆角问题(安卓直角) 解决办法 inpput{ -webkit-appearance: none; border-radius: 0px; } 2.ios ...

  7. 移动端安卓IOS对接H5项目遇到的坑

    最近做一个H5项目 退出的时候需要调用原生的弹框退出, 之前以为很简单,直接ajax调用后端退出接口即可.后来发现数据拿不到,因为状态用的是cookie存储, 后来想到ajax 传参数请求,后来还是拿 ...

  8. 浅谈 iOS 与 H5 的交互- JavaScriptCore 框架

    前言 小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCo ...

  9. iOS原生APP和H5交互-delegate和第三方

    一.原生代码中直接加载页面(拦截) 1.    具体案例 加载本地/网络HTML5作为功能介绍页 2.    代码示例 //本地 -(void)loadLocalPage:(UIWebView*)we ...

随机推荐

  1. C语言:通过指针对字符串进行拼接

    // //  main.c //  Pointer_stringcat // //  Created by ma c on 15/8/2. //  Copyright (c) 2015年 bjsxt. ...

  2. Objective-C:NSDectionary字典的常见操作

    NSDectionary字典:它是一个存储键值的容器,每一个键key都对应着一个值value,可以通过键key一次性找到目标值value,这是一个比较好的存储器,相比于数组而言,它明显提高了查询效率. ...

  3. window安装Scrapy———解决报错问题

    系统是WIN10 64位Python是3.5.2今天安装pip install Scrapy  来安装发现报错Microsoft Visual C++ 14.0 is required 检查发现电脑中 ...

  4. 创建spring boot项目启动报错遇到的问题

    1.Spring boot,Mybatis 启动报错 Failed to auto-configure a DataSource *************************** APPLICA ...

  5. IOS实现多媒体音频之音乐播放器

    随着智能手机市场越来越活跃,相应的app也变得五彩缤纷,各式各样,让你的app更吸引人多媒体技术不可避免.通过对音频和视频等控制让你的app更加丰富多彩,今天和大家一起研究下基本的音频使用.本文只提供 ...

  6. Android的硬件抽象层模块编写规范

    硬件抽象层模块编写规范 ​ Android系统的硬件抽象层以模块的形式来管理各个硬件訪问接口.每个硬件模块都相应有一个动态链接库文件.这些动态链接库文件的命令须要符合一定的规范.同一时候,在系统内部. ...

  7. 关于PHP写的投票网站之刷票终结版

    告诉大家一个坏消息,还是有刷票的行为,有图有真相: 倒数第三项是时间轴,倒数第二项是IP,倒数第一项是邮箱,你们要刷票,拦都拦不住呀呀呀呀呀呀!!!!! 看看这些时间的间隔,看看这些IP的地址,哎,再 ...

  8. C# 64位系统调用32位DLL异常解决办法(异常来自HRESULT :0x8007007E)

    解决办法如下 1.在IDE中将目标平台设置成x86(VS是在项目的属性->生成->目标平台) 2.如果DLL中调用了其他的DLL,需要将其他的DLL一同编译 3.有时DLL生成时会依赖于I ...

  9. 关于ASP.NET MVC中Form Authentication与Windows Authentication的简单理解

    一般互联网应用,如人人网,微博,都是需要用户登录的,如果用户不登陆,就不能使用此网站.所以,这里都是用FormAuthentication,要求用户填写用户名与密码,然后登录成功后,FormAuthe ...

  10. 自定义self.editButtonItem 改变自定义self.editButtonItem的背景图片

    一: // UIButton *editSome; 为全局变量,已开启ARC; editSome = [UIButton buttonWithType:UIButtonTypeCustom]; edi ...