Como conectar o TVML / JavaScriptCore ao UIKit / Objective-C (Swift)?

Tão longetvOS suporta duas maneiras de criar aplicativos de TV, TVML e UIKit, e não há menções oficiais sobre como misturar coisas para criar uma interface de usuário TVML (que é basicamente XML) com a contraparte nativa para a lógica do aplicativo e E / S ( como reprodução, streaming, persistência do iCloud etc.).

Então, qual é a melhor solução para misturarTVML eUIKit em um novotvOS aplicativo?

A seguir, tentei uma solução seguindo trechos de código adaptados dos Fóruns da Apple e perguntas relacionadas sobre a ligação JavaScriptCore a ObjC / Swift. Esta é uma classe de wrapper simples no seu projeto 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)")
    }
}

onde o delegado deve conformar umTVApplicationControllerDelegate:

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]?) {
    }
}

Neste ponto, o javascript é muito simples. Dê uma olhada nos métodos com parâmetros nomeados, você precisará alterar o nome do método da parte do contador 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');
    }

Agora, suponha que você tenha uma interface js muito complexa para exportar como

@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";
}

você pode fazer como

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

Neste ponto da parte do contador JS, você não fará o caso camel:

objectwrapper.bootNetworkUser(statusChanged,networkChanged,userChanged)

mas você vai fazer:

objectwrapper.boot(statusChanged,networkChanged,userChanged)

Finalmente, olhe para esta interface novamente:

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

O valor que JSValue * passou. É uma maneira de passar manipuladores de conclusão entreObjC/Swift eJavaScriptCore. Neste ponto do código nativo, todos vocês chamam com argumentos:

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

Nas minhas descobertas, vi que o MainThread travará se você não enviar no thread principal e assíncrono. Então, chamarei a chamada javascript "setTimeout" que chama o retorno de chamada do manipulador de conclusão.

Portanto, a abordagem que usei aqui é:

UsarJSExportAs levar o carro de métodos com parâmetros nomeados e evitar camelo caso homólogos javascript como callMyParam1Param2Param3UsarJSValue como parâmetro para se livrar dos manipuladores de conclusão. Use callWithArguments no lado nativo. Use funções javascript no lado JS;dispatch_async para manipuladores de conclusão, possivelmente chamando um setTimeout com 0 atraso no lado do JavaScript, para evitar que a interface do usuário congele.

[ATUALIZAR] Atualizei esta questão para ficar mais claro. Estou encontrando uma solução técnica para fazer a ponteTVML eUIKit a fim de

Entenda o melhor modelo de programação comJavaScriptCodeTenha a ponte certa deJavaScriptCore paraObjectiveC e vice versaTenha as melhores performances ao ligarJavaScriptCode deObjective-C

questionAnswers(2)

yourAnswerToTheQuestion