FlexibleHybrid
FlexHybrid 简化了 WKWebView 和 Native 之间的接口,包括异步处理。
它还提供了几个方便的功能来使用 WKWebView。
如何添加框架
在 Podfile 中添加
pod 'FlexHybridApp'
iOS 部署目标为 10.0
关键特性
- 它与 Android 版本 具有相似的编程规则和功能。
- WKWebView 和 Native 之间的接口以异步方式工作。
- 在 Web 上调用和返回 Promise。
- Native 在一个单独的 并发队列 上进行操作。
- 使用 Swift Closure 定义接口操作。
- 可以将数据传输到 模型对象。
- 通过指定能够进行接口操作的 URL,可以防止 非期望网站 从 Native 进行调用。
还包括其他特性...
FlexComponent
为了利用 FlexWebView 的功能,您必须使用 FlexComponent。
FlexComponent是用FlexWebView创建的,你还可以在声明FlexWebView时对其进行设置。
FlexComponent还包括WebView的WKWebViewConfiguration作为参数。
界面基本使用
基本上,界面可以按照以下模式进行注册和使用。
所有界面操作都是异步的。
在Web上,它将变成挂起状态,直到发生响应。
Web到本地
界面注册
界面必须在页面加载到FlexWebView之前设置。
// in swift
var component = FlexComponent()
component.setInterface("funcName") { args in
return "received from web - \(args[0]?.toString() ?? "no value"), return to web - \(100)"
}
var flexWebView = FlexWebView(frame: self.view.frame, component: component)
flexWebView.load(someUrl)
使用界面
// in js
const test = async (req) => {
const res = await $flex.funcName(req);
console.log(res); // received from web - 200, return to web - 100
};
test(200);
本地到Web
界面注册
$flex对象加载后(可以在$flex Load时间上检查window.onFlexLoad函数),则注册界面。
// in js
window.onFlexLoad = () => {
$flex.web.funcName = async (req) => {
return await new Promise((resolve) => {
setTimeout(() => resolve(`received from web - ${req}`), 100);
});
};
};
使用接口。
// in swift
component.evalFlexFunc("funcName", "sendData") { response in
print(response.toString()!) // received from web - sendData
}
高级接口使用
FlexData
从Web接收的数据被转换为FlexData对象以实现类型安全使用。
在Web到原生的接口中,来自Web的函数传递的参数将被转发到Array
// in js
$flex.funcName("test1", 2, 3.1, true, [0, 1, 2], { test: "object" }, "reified");
component.setInterface("funcName") { args in
if (args == nil) return
var first = args[0].asString() // "test"
var second = args[1].asInt() // 2
var third = args[2].asDouble() // 3.1
var fourth = args[3].asBool() // true
var fifth = args[4].asArray() // array of FlexData(0), FlexData(1), FlexData(2)
var sixth = args[5].asDictionary() // map of first key - test, value - FlexData("object")
var seventh: String? = args[6].reified() // "reified"
}
模型对象
用于接口的数据可以作为模型对象使用。
此时,以下规则适用。
- 模型对象必须 继承Codable。
- 在Web中,它被转换为一个对象形式。
- 当从原生接收模型对象作为参数时,您必须传递与Web中相应模型对应的唯一一个对象。
// in swift
struct TestModel: Codable {
var name: String
var data2: TestModel2
}
struct TestModel2: Codable {
var testInt: Int
}
struct ArgsTestModel: Codable {
var testModel: TestModel
}
component.setInterface("modelTest") { args in
return TestModel("test", TestModel2(2000))
}
component.setInterface("modelArgsTest") { (req: ArgsTestModel?) -> Void in
print(req?.testModel.data2.testInt) // 2000
}
// in js
const test = async () => {
const model = await $flex.modelTest(); // model is { name: 'test', data2: { testInt: 2000 } }
await $flex.modelArgsTest({ testModel: model });
};
test();
动作接口
在Web到原生的接口中,除了指定的闭包代码块之外,这是一种返回值的方式。
动作对象允许你在代码的期望位置返回值。
此时,Web处于 挂起 状态,直到发生响应。
此外,已响应一次的动作对象不能再次使用。
var mAction: FlexAction? = null
struct LocationResult: Codable {
var latitude: Double?
var longtitude: Double?
}
component.setAction("actionTest") { (action, _) in
self.mAction = action
self.getLocation()
}
func getLocation() {
let status = CLLocationManager.authorizationStatus()
var locationResult = LocationResult();
switch status {
case .authorizedAlways, .authorizedWhenInUse :
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.startUpdatingLocation()
let coor = self.locationManager.location?.coordinate
mAction?.promiseReturn(
LocationResult(latitude: Double(coor?.latitude ?? 0), longtitude: Double(coor?.longitude ?? 0))
)
break
default:
mAction?.promiseReturn()
break
}
}
推荐声明闭包
这是一种便于声明和组织定义接口行为的闭包特征。
您可以通过FlexClosure类中预定义的函数创建闭包。
var closureVar = FlexClosure.interface { args in
... some job
}
var closureActionVar = FlexClosure.action { (action, args) in
... come job
}
component.setInterface("closureVarTest", closureVar)
component.setAction("closureActionVarTest", closureActionVar)
Web至本地接口超时设置
由于接口操作是异步的,Web端可能会陷入无限等待状态。
因此,可以设置接口的超时,当发生超时时,会切换到拒绝状态。
如果未设置超时,默认值为60000毫秒。
设置默认超时
您可以为超时指定默认值。如果未为每个接口设置超时,则默认设置相应的值。
将值设为零不会导致超时并无限期等待。
单位是毫秒。
var timeout = 1000
component.setInterfaceTimeout(timeout)
为每个接口指定超时
在设置接口时,您可以指定该接口的超时时间。
将值设为零不会导致超时并无限期等待。
单位是毫秒。
var timeout = 200
component.setInterface("funcName", timeout) { args in }
接口事件监听器
初始化接口模块时,会监听接口的成功、失败及超时的相关事件。
// Listen for specific events
component.addEventListener(FlexEvent.EXCEPTION) { (type, url, funcName, msg) in
print("type: \(type.name) url: \(url) funcName: \(funcName) msg: \(msg)")
}
// Listen to all events
var AllListener = { (type, url, funcName, msg) in
print("type: \(type.name) url: \(url) funcName: \(funcName) msg: \(msg)")
}
flexWebView.addEventListener(AllListener)
// Remove specific EventListener
flexWebView.removeEventListener(AllListener)
// Remove all EventListeners
flexWebView.removeAllEventListener()
FlexWebView特性
URL限制
这是一个防止加载到非预期网站并设置是否允许特定URL接口的功能。
该功能通过WKContentRule实现,因此在使用时需要小心,因为它可以通过WKWebViewConfiguration中的removeAllContentRuleList函数被删除。
BaseUrl
BaseUrl是在不需要URL限制的情况下设置接口可用性的功能。
如果未设置AllowUrlList和BaseUrl,FlexWebView允许访问所有网站,但接口功能不可用。
如果仅设置BaseUrl,允许访问所有网站,并且接口仅对匹配BaseUrl的URL打开。
component.setBaseUrl("www.myurl.com")
在设置URL时可以使用正则表达式。
component.setBaseUrl(".*.myurl.com")
AllowUrlList
仅适用于iOS 11.0及以上版本。
设置AllowUrlList会阻止访问除已设置URL和BaseUrl以外的所有URL。
component.addAllowUrl(".*.myurl.com")
在设置URL时允许接口,请将true添加到addAllowUrl函数的第二个canFlexLoad属性中。
component.addAllowUrl(".*.myurl.com", canFlexLoad: true)
自动管理Cookie
仅适用于iOS 11.0及以上版本。
这是一个非常基本的功能,因此请直接在出现问题时在实现中直接实现与Cookie相关功能。
这是一个自动维护Cookie的功能。
默认值为不活跃,激活功能时自动运行。
在应用中启用该功能的FlexWebView共享所有Cookie。
component.setAutoCookieManage(true) // activate
component.setAutoCookieManage(true, clearAll: true) // activate and delete all cookies
Web控制台消息输出。
显示Web控制台的.log、debug、error、warn和info消息到xcode的输出窗口中。
默认情况下已启用。
此输出可能与Web上的控制台消息不同。
component.setShowWebViewConsole(true)
FileAccess
一次设置allowAccessFromFileURLs和allowUniversalAccessFromFileURLs的能力。
component.setAllowsUrlAccessInFile(true)
在js中使用
$flex Object
$flex Object是由FlexWebView和Promise之间的接口组成的对象。
在webview加载页面时,$flex会在页面运行时声明在web页面中。
当$flex加载完成后,您可以检查window.onFlexLoad函数。
$flex也可以在任何可访问的框架中使用。(例如)不违反Cross-Origin规则的自定义框架。
$ flex对象的组件如下。
window.onFlexLoad; // $flex is called upon completion of loading.
$flex; // Object that contains functions that can call Native area as WebToNative
$flex.version; // get Library version
$flex.web; // Object used to add and use functions to be used for NativeToWeb
$flex.device; // Current Device Info
$flex.isAndroid; // false
$flex.isiOS; // true
$fles.isScript; // false
ToDo
应用Swift 5.5的async awit。
Flutter版本FlexHybirdApp。