gpt4 book ai didi

objective-c - 如何将 TVML/JavaScriptCore 桥接到 UIKit/Objective-C (Swift)?

转载 作者:太空狗 更新时间:2023-10-30 03:14:24 25 4
gpt4 key购买 nike

到目前为止,tvOS 支持两种制作电视应用程序的方法,TVML 和 UIKit,并且没有官方提及如何混合使用 TVML(基本上是 XML)用户界面应用程序逻辑和 I/O(如播放、流式传输、iCloud 持久性等)的 native 对应部分。

那么,在新的 tvOS 应用中混合 TVMLUIKit 的最佳解决方案是什么?

在下文中,我尝试了一个解决方案,该解决方案遵循从 Apple 论坛改编的代码片段以及有关 JavaScriptCore 到 ObjC/Swift 绑定(bind)的相关问题。这是您的 Swift 项目中的一个简单包装器类。

import UIKit
import TVMLKit
@objc protocol MyJSClass : JSExport {
func getItem(key:String) -> String?
func setItem(key:String, data:String)
}
class MyClass: NSObject, MyJSClass {
func getItem(key: String) -> String? {
return "String value"
}

func setItem(key: String, data: String) {
print("Set key:\(key) value:\(data)")
}
}

委托(delegate)必须符合 TVApplicationControllerDelegate:

typealias TVApplicationDelegate = AppDelegate
extension TVApplicationDelegate : TVApplicationControllerDelegate {

func appController(appController: TVApplicationController, evaluateAppJavaScriptInContext jsContext: JSContext) {
let myClass: MyClass = MyClass();
jsContext.setObject(myClass, forKeyedSubscript: "objectwrapper");
}

func appController(appController: TVApplicationController, didFailWithError error: NSError) {
let title = "Error Launching Application"
let message = error.localizedDescription
let alertController = UIAlertController(title: title, message: message, preferredStyle:.Alert ) self.appController?.navigationController.presentViewController(alertController, animated: true, completion: { () -> Void in
})
}

func appController(appController: TVApplicationController, didStopWithOptions options: [String : AnyObject]?) {
}

func appController(appController: TVApplicationController, didFinishLaunchingWithOptions options: [String : AnyObject]?) {
}
}

至此javascript就很简单了就好了。查看带有命名参数的方法,您将需要更改 javascript 计数器部分方法名称:

   App.onLaunch = function(options) {
var text = objectwrapper.getItem()
// keep an eye here, the method name it changes when you have named parameters, you need camel case for parameters:
objectwrapper.setItemData("test", "value")
}

App. onExit = function() {
console.log('App finished');
}

现在,假设您有一个非常复杂的 js 接口(interface)可以像这样导出

@protocol MXMJSProtocol<JSExport>
- (void)boot:(JSValue *)status network:(JSValue*)network user:(JSValue*)c3;
- (NSString*)getVersion;
@end
@interface MXMJSObject : NSObject<MXMJSProtocol>
@end
@implementation MXMJSObject
- (NSString*)getVersion {
return @"0.0.1";
}

你可以这样做

JSExportAs(boot, 
- (void)boot:(JSValue *)status network:(JSValue*)network user:(JSValue*)c3 );

此时在 JS Counter 部分你不会做驼峰式大小写:

objectwrapper.bootNetworkUser(statusChanged,networkChanged,userChanged)

但是你要做的是:

objectwrapper.boot(statusChanged,networkChanged,userChanged)

最后再看看这个界面:

- (void)boot:(JSValue *)status network:(JSValue*)network user:(JSValue*)c3;

传入的值 JSValue* 是一种在 ObjC/SwiftJavaScriptCore 之间传递完成处理程序的方法。此时,在 native 代码中,您将使用参数进行所有调用:

dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *state = [NSNumber numberWithInteger:status];
[networkChanged.context[@"setTimeout"]
callWithArguments:@[networkChanged, @0, state]];
});

在我的发现中,我发现如果不在主线程和异步上分派(dispatch),MainThread 将会挂起。因此,我将调用调用完成处理程序回调的 javascript“setTimeout”调用。

所以我在这里使用的方法是:

  • 使用 JSExportAs 处理带有命名参数的方法,避免使用 callMyParam1Param2Param3 等驼峰式 javascript 对应方法
  • 使用 JSValue 作为参数来摆脱完成处理程序。在 native 端使用 callWithArguments。在 JS 端使用 javascript 函数;
  • dispatch_async 用于完成处理程序,可能会在 JavaScript 端调用 setTimeout 0 延迟,以避免 UI 卡住。

[更新]为了更清楚,我已经更新了这个问题。我正在寻找桥接 TVMLUIKit 的技术解决方案,以便

  • 了解使用 JavaScriptCode 的最佳编程模型
  • 拥有从 JavaScriptCoreObjectiveC 的正确桥梁,并且反之亦然
  • Objective-C 调用 JavaScriptCode 时具有最佳性能

最佳答案

WWDC Video解释如何在 JavaScript 和 Obj-C 之间进行通信

这是我从 Swift 到 JavaScript 的通信方式:

//when pushAlertInJS() is called, pushAlert(title, description) will be called in JavaScript.
func pushAlertInJS(){

//allows us to access the javascript context
appController!.evaluateInJavaScriptContext({(evaluation: JSContext) -> Void in

//get a handle on the "pushAlert" method that you've implemented in JavaScript
let pushAlert = evaluation.objectForKeyedSubscript("pushAlert")

//Call your JavaScript method with an array of arguments
pushAlert.callWithArguments(["Login Failed", "Incorrect Username or Password"])

}, completion: {(Bool) -> Void in
//evaluation block finished running
})
}

这是我从 JavaScript 到 Swift 的通信方式(它需要在 Swift 中进行一些设置):

//call this method once after setting up your appController.
func createSwiftPrint(){

//allows us to access the javascript context
appController?.evaluateInJavaScriptContext({(evaluation: JSContext) -> Void in

//this is the block that will be called when javascript calls swiftPrint(str)
let swiftPrintBlock : @convention(block) (String) -> Void = {
(str : String) -> Void in

//prints the string passed in from javascript
print(str)
}

//this creates a function in the javascript context called "swiftPrint".
//calling swiftPrint(str) in javascript will call the block we created above.
evaluation.setObject(unsafeBitCast(swiftPrintBlock, AnyObject.self), forKeyedSubscript: "swiftPrint" as (NSCopying & NSObjectProtocol)?)
}, completion: {(Bool) -> Void in
//evaluation block finished running
})
}

[更新] 对于那些想知道“pushAlert”在 javascript 端是什么样子的人,我将分享一个在 application.js 中实现的示例

var pushAlert = function(title, description){
var alert = createAlert(title, description);
alert.addEventListener("select", Presenter.load.bind(Presenter));
navigationDocument.pushDocument(alert);
}


// This convenience funnction returns an alert template, which can be used to present errors to the user.

var createAlert = function(title, description) {

var alertString = `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<alertTemplate>
<title>${title}</title>
<description>${description}</description>

</alertTemplate>
</document>`

var parser = new DOMParser();

var alertDoc = parser.parseFromString(alertString, "application/xml");

return alertDoc
}

关于objective-c - 如何将 TVML/JavaScriptCore 桥接到 UIKit/Objective-C (Swift)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33081565/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com