用JavaScriptCore做android和iOS都兼容的JS-NativeSDK

2023-05-16

最近在给公司做一个JS-Native的SDK,就是用于JS和原生之间的交互。
使用场景上主要还是webView,那么原先的url拦截的方式已经不再考虑,我们使用了iOS7之后的JavaScriptCore.framework。


总体来说,苹果的JavaScriptCore的API是非常易用的,主要操作步骤如下:
1.获取一个JSContext。

_jsContext = [_webView valueForKeyPath:
@"documentView.webView.mainFrame.javaScriptContext"];

2.处理某个JS端调起的方法,比如log

_jsContext[@"log"] = ^() {
        NSArray *args = [JSContext currentArguments];
        for (id obj in args) {
            //需要注意这里的obj都还是JSValue
            NSLog(@"%@",obj);
        }
    };

3.调用JS端执行某个JS方法

[_jsContext 
evaluateScript:@"log('arg1')"];
[_jsContext 
evaluateScript:@"logCallback('arg1')"];

4.重定义某个JS端的方法(其实和3是一种,不过特殊了点)

[_jsContext evaluateScript:@"checkAPI = function(){\
     return [\
     'selectImage',\
     'startRecord',\
     'login',\
     ];\
     }"];

掌握了以上4步,基本上在iOS端和JS的交互就完全OK了。
接着我们开始和android端h5端进行联调。
到这里,我们发现了一个问题:
android端JS方法调用原生方法时,需要指定interfaceName,所以他们的JS调用方式是这样的:

xxname.log('arg1');

前面多出来了xxname,这种方式下,我们直接使用JSContext进行监听处理是不行的

//这个不能被执行到
_jsContext[@"xxname.log"] = ^() {
        NSArray *args = [JSContext currentArguments];
        for (id obj in args) {
            //需要注意这里的obj都还是JSValue
            NSLog(@"%@",obj);
        }
    };

那么怎么办呢?胜利在望的时候卡住了?难道要让h5那边调用的时候按平台区分么?如果是iOS平台就调用log(‘xx’),android就调用xxname.log(‘xx’)??

还好,我们这么犀利怎么会解决不了这样的问题。
这里我给大家介绍两种方法解决:

方案一:
使用JSExport,达到和android类似处理效果
步骤如下:
1.定义WebViewJSHelperProtocol协议实线JSExport协议
并在协议中定义出所有JS端要调用的方法

@protocol WebViewJSHelperProtocol<JSExport>
-(void)log:(NSString*)arg;
@end

2.定义类实现该协议

@interface WebViewJSHelper()<WebViewJSHelperProtocol>
@end

@implementation WebViewJSHelper
-(void)log:(NSString*)arg{
    NSLog(@"%@",arg);
}
@end

3.注册该类的实例到JSContext

WebViewJSHelper *_webViewJSHelper = [[WebViewJSHelper alloc]init];
_jsContext[@"xxname"] = _webViewJSHelper;

到此,JS调用xxname.log方法时,会进入我们iOS端定义的log方法中执行。
关于JSExport还有一些定义别名之类的,感兴趣的同学可以自行看API或网上文档。
主要注意的是,这里不要出现_jsContext[@”xxname”] = self;这样的代码,因为会导致self实例被JS端持有而内存不释放的问题。

方案二:
这个方案的操作方式就简单多了,对比方案一,无需定义实现的原生方法,操作如下:
1.随便定义一个类加上JSExport协议

@interface WebViewJSExport : NSObject<JSExport>
@end
@implementation WebViewJSExport
@end

2.注册给JSContext

_jsContext[@"xxname"] = [WebViewJSExport new];

3.处理某个JS端调起的方法

//定义不含xxname的正常js方法
_jsContext[@"log"] = ^() {
        NSArray *args = [JSContext currentArguments];
        for (id obj in args) {
            //需要注意这里的obj都还是JSValue
            NSLog(@"%@",obj);
        }
    };
//重定义xxname.log方法
[_jsContext evaluateScript:@"xxname.log = log"];

好了,现在整套功能都可以使用了。

上面方案二的方式个人觉得优点更多一些,首先更贴近JS习惯,其次不需要定义那么多的方法,而且对于js端调用来说,不定参数个数也更容易些。


这篇文章的最后,讲一点小的注意事项:
1. 使用 NSArray *args = [JSContext currentArguments];得到的args,内部都是JSValue,千万注意这一点,如果想要使用,最好转成相应的类型,比如[obj toString]之类的,具体可以看JSValue的头文件
2. 要注意循环引用的问题,不要写出 _jsContext[@”xxname”] = self; 这样的代码来,其他的就是block中的了,老生常谈不再细说。
3. 要注意JS端和原生端生命周期的问题
两端的内存管理方式不一样,JS端是GC,我们是引用计数,一般情况不会有生命周期的问题,但是必要时,需要使用JSVirtualMachine包装一下,这块我也还在学习,希望大家注意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用JavaScriptCore做android和iOS都兼容的JS-NativeSDK 的相关文章

  • Android 辅助功能服务检测通知

    我试图让我的应用程序在显示通知时进行检测 我已在设置应用程序中启用它并且onServiceConnected确实接到电话 但是当我创建通知或通过 gmail 应用程序接收电子邮件时 什么也没有发生 onAccessibilityEvent没
  • TextView 宽度匹配drawableTop 宽度

    有什么办法可以使TextView width匹配复合可绘制宽度 XML 例如对于 xml 代码
  • iOS 11 浮动 TableView 标题

    有一个应用程序包含多个部分 展开 时每个部分有几行 折叠 时没有 每个部分都有一个部分标题 使用以下子类重用它们UITableViewHeaderFooterView等等 到目前为止一切顺利 然后在 iOS 11 中 我使用了可视化调试器
  • 在 Android 中跨单元测试和仪器测试共享资源

    现在谷歌已经添加了实验单元测试支持 http tools android com tech docs unit testing support 如何在单元测试和仪器测试之间共享资源 例如 假设我有一个TestUtils java我希望在单元
  • Android NDK 支持区域设置吗?

    我真正想做的就是使用格式化日期strftime x 以正确的顺序 在大多数平台上调用setlocale 足够 在 Android 上 我不断收到 美国日期 那么 Android 不支持语言环境吗 No setlocale and strft
  • 将人类日期(当地时间 GMT)转​​换为日期

    我正在服务器上工作 服务器正在向我发送 GMT 本地日期的日期 例如Fri Jun 22 09 29 29 NPT 2018在字符串格式上 我将其转换为日期 如下所示 SimpleDateFormat simpleDateFormat ne
  • UICollectionReusableView 方法未被调用

    我希望我的部分位于UICollectionView有一个带有图像的标题 我已按照以下步骤操作 在故事板中 分配了一个标题作为我的附件UICollectionView 给它一个标识符 创建了一个子类UICollectionReusableVi
  • NSDateFormatter:根据 currentLocale 的日期,不包含年份

    这不会太难吧 我想显示不带年份的日期 例如 8 月 2 日 美国 或 02 08 德国 它也必须适用于许多其他语言环境 到目前为止 我唯一的想法是对年份进行正常格式 然后从生成的字符串中删除年份部分 我认为你需要看一下 NSString d
  • 将语音添加到自定义 UIMenuController

    我创建了一个自定义UIMenuController in a UIWebView但它似乎摆脱了 说出选择 选项UIMenuController在那之后 所有测试设备上的 偏好设置 中都打开了发言选择选项 并且它出现在其他应用程序中 包括非
  • Android SHA1 发布密钥库无法与 Google 地图配合使用

    我正在使用 Google Maps Android API 但遇到了一些问题 我正在使用 android studio 签署我的 apk 在 android keystore jks 创建一个 另外 我选择 发布 作为其中的类型 我已经使用
  • 所有针对 iTunes Connect 的构建,导入此构建时出错 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我将构建上传到应用程序商店 之后它在活动中显示错误 任何人都可以帮帮我 SOLVED 转到构建设置 gt 搜索 bitcode gt 转启
  • Android Studio代理设置构建错误

    每当我尝试在 Android Studio 中构建应用程序时 都会收到以下错误 Error 169 254 16 169 254 16 Will ignore proxy settings for these hosts 我收到错误 5 次
  • 由于 2.23 导致 iOS 应用程序被拒绝 - iOS 数据存储指南

    以下是 Apple 关于拒绝的消息 2 23 应用程序必须遵循 iOS 数据存储指南 否则将被拒绝 2 23 详情 在启动和内容下载时 您的应用程序会存储 6 5 MB 这并不意味着 遵守 iOS 数据存储指南 下一步 请验证只有用户使用您
  • 如何使用 isInEditMode() 在编辑器中查看自定义视图的布局

    我必须编辑一个具有自定义视图的软件 当我尝试编辑布局 xml 时 Eclipse 告诉我 在自定义视图中使用 View isInEditMode 可以在显示时跳过代码 在日食中 但我不知道how and where我必须使用isInEdit
  • Android:分配内存失败

    我正在尝试创建一个具有 2047 mb 内存的模拟器 当我运行它时 我收到此错误 2011 02 22 14 24 14 Emulator 2011 02 22 14 24 14 Emulator This application has
  • Xcode 在代码签名身份中看不到我的开发人员证书

    我续订了 IOS 开发人员证书 从钥匙串中删除了旧证书 然后单击了我的证书 钥匙串中的一切看起来都很正常 我有分发 开发人员 WWDC 证书 每个配置文件看起来都有效 并带有绿色标记 在组织器中的团队和配置文件部分下 但在代码签名身份下的
  • 使用 nib 作为带有 nib 类的表节标题

    我想创建一个加载 nib 文件并将其设置为标题 UIView 的节标题 这个 nib 文件还将有一个关联的类 其中插座和操作连接到 因此我想像平常一样使用 nib 加载该类 我在网上搜索并找到了几个类似的答案 但我找不到任何适合我的答案 经
  • 进入后台时 Alamofire 请求卡住?

    我正在使用 Alamofire 调用 Web 服务 该服务需要相当长的时间才能加载 如果应用程序进入后台 当我返回应用程序时 我会被加载程序卡住 我想这是因为调用永远不会向我的完成处理程序返回任何内容 我该如何解决这个问题 您可以使用后台抓
  • 选择 UITableViewCell 时 UIView 背景颜色消失

    我在界面生成器中构建了一个简单的 tableViewCell 它包含一个包含图像的 UIView 现在 当我选择单元格时 会显示默认的蓝色选择背景 但 UIView 的背景颜色消失了 我的 UITableViewCell 的实现文件没有做任
  • 如何模拟ARM处理器运行环境并加载Linux内核模块?

    我尝试加载我的vmlinux into gdb并使用 ARM 内核模拟器 但我不明白为什么我会得到Undefined target command sim 这是外壳输出 arm eabi gdb vmlinux GNU gdb GDB 7

随机推荐

  • Linux查看日志常用命令

    第一种 xff1a 查看实时变化的日志 比较吃内存 最常用的 xff1a tail f app log 默认最后10行 xff0c 相当于增加参数 n 10 tail 200f app log 最后200行 xff0c 某一时刻往前推 Ct
  • ubuntu查看文件和文件夹大小

    在实际使用ubuntu时候 xff0c 经常要碰到需要查看文件以及文件夹大小的情况 有时候 xff0c 自己创建压缩文件 xff0c 可以使用 ls hl 查看文件大小 参数 h 表示Human Readable xff0c 使用GB MB
  • NLTK下载错误的终极解决办法

    Downloading package brown to C Users Ken AppData Roaming nltk data Error downloading 39 brown 39 from lt https raw githu
  • Tensorboard 不显示数据的问题

    No dashboards are active for the current data set Probable causes You haven 39 t written any data to your event files Te
  • Pytorch学习(2)——训练词向量的代码

    教程 xff1a https www bilibili com video BV1vz4y1R7Mm p 61 2 span class token keyword import span torch span class token ke
  • Windows 在不修改主题色的情况下将标题栏修改为黑色

    有些软件使用深色模式之后标题栏仍然是白色的 xff0c 很不美观 如果在 Windows 10 的设置中 xff0c 将个性化 颜色 在以下区域显示主题色 标题栏和窗口边框 选中 xff0c 那么标题栏可以带颜色 此时如果将主题色改为彩色
  • 解决debian(jessie)没有声音的问题

    先检查系统声卡驱动 lspci grep Audio 00 1b 0 Audio device Intel Corporation 82801I ICH9 Family HD Audio Controller rev 03 说明系统已经识别
  • 笔记类软件总结

    我大致把笔记类软件分为三类 xff1a 传统文档 思维导图 专业软件 1 传统文档 Typora 最经典的本地软件应该是 Typora 支持 Markdown 的实时预览 xff0c 界面简洁美观 使用基于 Chromium 浏览器的 El
  • Golang Map 基本原理

    Go 语言中的 map 即哈希表 哈希表把元素分到多个桶里 xff0c 每个桶里最多放8个元素 在访问元素时 xff0c 首先用哈希算法根据 key 和哈希表种子获得哈希值 暂将其命名为 h xff0c 然后利用 h 的低 b b b 位得
  • Go 汇编器指南

    A Quick Guide to Go s Assembler Go汇编器指南 This document is a quick outline of the unusual form of assembly language used b
  • [golang] 什么情况下reflect.IsValid 返回 false?

    https stackoverflow com questions 39011295 when does reflect isvalid return false 总结成一句话 xff1a IsValid 表示是否 Value 是否 wra
  • IPv6的DNS,设置DNS

    来自下一代互联网国家工程中心的最新消息 xff0c 该中心正式宣布推出IPv6公共DNS xff1a 240c 6666 xff0c 这是面向全球免费提供的公共DNS服务 同时 xff0c 还有一个备用DNS xff1a 240c 6644
  • MongoDB 查询包含某字符串的记录

    34 key 34 regex 广东
  • Anaconda使用conda连接网络出现错误(CondaHTTPError: HTTP 000 CONNECTION FAILED for url)

    进入 HOMEPATH 目录 编辑其中的 condarc 文件 删除 default 将 https 改成 http 转载自 Anaconda使用conda连接网络出现错误 CondaHTTPError HTTP 000 CONNECTIO
  • Win10 EFI启动文件被删的修复办法

    首先确保EFI分区存在 没有的话可以进入PE创建 首先是不成功的办法 xff1a 用PE里的EFI分区修复 xff0c 成功把Win7变成了EFI启动 xff08 以前梦寐以求的 xff09 xff0c 但是Win10一直修复失败 xff0
  • 关于UITabBarController的UITabBar隐藏问题

    最开始的时候我用的 void hideTabBar if self tabBarController tabBar hidden 61 61 YES return UIView contentView if self tabBarContr
  • NSAttributedString宽高计算小技巧

    通常对于CoreText之类自己实现绘制的控件来说 xff0c 计算富文本的宽高其实需要依赖CTFramesetterSuggestFrameSizeWithConstraints这个方法 但有些时候 xff0c 我们可能只是使用UILab
  • 拦截器获取HttpServletRequest里body数据

    一 问题 通过在拦截器中获取request中的json数据 xff0c 我们可以实现对参数进行校验和改写 问题是参数只能在拦截器里获取一次 xff0c 往后在controller层就无法获取数据 xff0c 提示body为空 在网上查找资料
  • iOS开发小技巧之--WeakSelf宏的进化

    我们都知道在防止如block的循环引用时 xff0c 会使用 weak关键字做如下定义 xff1a span class hljs keyword weak span typeof span class hljs keyword self
  • 用JavaScriptCore做android和iOS都兼容的JS-NativeSDK

    最近在给公司做一个JS Native的SDK xff0c 就是用于JS和原生之间的交互 使用场景上主要还是webView xff0c 那么原先的url拦截的方式已经不再考虑 xff0c 我们使用了iOS7之后的JavaScriptCore