2017-04-06 13 views
5

Tôi đã tạo ra lớp sau (phiên bản đặc), heres một tham chiếu đến tập tin đầy đủ https://github.com/cotyembry/CastRemoteNative/blob/7e74dbc56f037cc61241f6ece24a94d8c52abb32/root/ios/CastRemoteNative/NativeMethods.swiftGửi sự kiện để JS từ nhanh chóng hoặc Objective-C

@objc(NativeMethods) 
class NativeMethods: RCTEventEmitter { 
    @objc(sendEventToJSFromJS) 
    func sendEventToJSFromJS { 
    self.emitEvent(eventName: "test", body: "bodyTestString") 
    } 
    func emitEvent(eventName: String: body: Any) { 
    self.sendEvent(withName: eventName, body: body) 
    } 
} 

này hoạt động hoàn hảo và cháy nghe gọi lại tôi đó là trong mã javascript của tôi khi tôi gọi phương thức emitEvent như sau, một đoạn thay đổi từ https://github.com/cotyembry/CastRemoteNative/blob/7e74dbc56f037cc61241f6ece24a94d8c52abb32/root/js/Components/ChromecastDevicesModal.js

từ phía javascript

import { 
    NativeModules, 
    NativeEventEmitter 
} from 'react-native' 

//here I bring in the swift class to use inside javascript 
var NativeMethods = NativeModules.NativeMethods; 

//create an event emitter to use to listen for the native events when they occur 
this.eventEmitter = new NativeEventEmitter(NativeMethods); 
//listen for the event once it sends 
this.subscription = this.eventEmitter.addListener('test', (body) => { console.log('in test event listener callback', body)}); 

NativeMethods.sendEventToJSFromJS() //call the native method written in swift 

tôi chỉ đơn giản có sendEventToJSFromJS phương pháp gọi trên báo chí nút trong javascript

Một lần nữa, công trình này và console.log('in test event listener callback', body) công trình mã và chạy về phía javascript

Issue của tôi nơi này không làm việc:

Nếu tôi đã làm như sau trong tập tin nhanh chóng sau khi xác định lớp, điều này sẽ không làm việc:

var nativeMethodsInstance = nativeMethods() 
nativeMethodsInstance.sendEventToJSFromSwift() 

Tại sao? Vì lỗi sau được ném:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'bridge is not set. This is probably because you've explicitly synthesized the bridge in NativeMethods, even though it's inherited from RCTEventEmitter.' 

Vì vậy, khi tạo instance của NativeMethods, so với ... sự khác biệt là gì?

Để biết thêm thông tin:

Objective-C được cây cầu cùng không đặt vấn đề khi tôi viết những đoạn cùng một đoạn mã trong .h và .m file thay vì trong các tập tin .swift

tôi tìm thấy nơi thông báo lỗi là nhận được in trong mã nguồn gốc, nhưng nó chỉ có biến

_bridge 

và đang kiểm tra để xem nếu nó là nil

Các tập tin không có lỗi này xuất phát từ là:

RCTEventEmitter.h 
RCTEventEmitter.c 

đây là đoạn đầy RCTEventEmitter.c

- (void)sendEventWithName:(NSString *)eventName body:(id)body 
{ 


    RCTAssert(_bridge != nil, @"bridge is not set. This is probably because you've " 
     "explicitly synthesized the bridge in %@, even though it's inherited " 
     "from RCTEventEmitter.", [self class]); 

    if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) { 
    RCTLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`", 
       eventName, [self class], [[self supportedEvents] componentsJoinedByString:@"`, `"]); 
    } 
    if (_listenerCount > 0) { 
    [_bridge enqueueJSCall:@"RCTDeviceEventEmitter" 
        method:@"emit" 
         args:body ? @[eventName, body] : @[eventName] 
       completion:NULL]; 
    } else { 
    RCTLogWarn(@"Sending `%@` with no listeners registered.", eventName); 
    } 
} 

đâu giá trị _bridge này được thiết lập và làm thế nào nó được thiết lập để tôi có thể biết, trong trường hợp nó là không làm thế nào để thiết lập nó

tôi tìm thấy những điều sau đây cũng trong RCTEventEmitter.h

@property (nonatomic, weak) RCTBridge *bridge; 

Trong lỗi được đưa ra nó đề cập đến cây cầu được thừa hưởng trong RCTEventEmitter, vì vậy đây có thể là một vấn đề với phần weak đến tài sản bridge?

Hoặc tôi có cần phải thay đổi chiến lược của mình trong cách tôi làm tất cả điều này cùng nhau không?

Tôi biết nó có thể có được một cái gì đó để làm với tôi không hiểu cặn kẽ về

@synthesize bridge = _bridge; 

một phần của mã và tất cả các ngôn ngữ được trộn lẫn trong doesnt giúp ích nhiều cho lol ...

này thực sự khó khăn, vì vậy bất kỳ trợ giúp nào cũng sẽ được đánh giá cao! Cảm ơn rất nhiều vì thời gian của bạn

đây là một liên kết đến các dự án đầy đủ khi mã lịch sử dự án đại diện cho mã từ câu hỏi của tôi ở trên (kể từ khi tôi có kể từ khi thay đổi thực hiện để dự án):

https://github.com/cotyembry/CastRemoteNative/tree/7e74dbc56f037cc61241f6ece24a94d8c52abb32

Trả lời

1

I figured it out

Cảnh báo: giải pháp này sử dụng một phương pháp NỮA phản ứng phương pháp tự nhiên - tôi không thể tìm ra cách để "đúng" kế thừa từ RCTEventEmitter và gửi một sự kiện ... eve Hiện ry Tôi cố gắng để các _bridge sẽ kết thúc được nil

Hãy chắc chắn rằng Swift là cầu nối để Objective C (nếu bạn đang sử dụng nhanh chóng để gửi sự kiện để javascript)

Do Không tạo thể hiện của các các mô đun Native được xuất (cho dù chúng được viết bằng Swift hoặc Objective C)

Hãy để React thực hiện cơ bản của Native làm điều này và cho mỗi lớp cần gửi sự kiện, xuất khẩu mã thực thi C (Mô-đun gốc) để Phản hồi-Gốc. Điều này cho phép javascript để có thể lắng nghe những sự kiện

var publicBridgeHelperInstance = PublicBridgeHelper() //instantiate the the objective c class from inside the .swift file to use later when needing to get a reference to the bridge to send an event to javascript written in react native 

@objc(DeviceManager)    //export swift module to objective c 
class DeviceManager: NSObject { 

    @objc(deviceDidComeOnline:) //expose the function to objective c 
    public func deviceDidComeOnline(_ device: GCKDevice) { 
    //imagine this deviceDidComeOnline function gets called from something from the Native code (totally independent of javascript) - honestly this could be called from a native button click as well just to test it works... 

    //emit an event to a javascript function that is a in react native Component listening for the event like so: 

    //1. get a reference to the bridge to send an event through from Native to Javascript in React Native (here is where my custom code comes in to get this to actually work) 
    let rnBridge = publicBridgeHelperInstance.getBridge() //this gets the bridge that is stored in the AppDelegate.m file that was set from the `rootView.bridge` variable (more on this later) 

    //(if you want to print the bridge here to make sure it is not `nil` go ahead: 
    print("rnBridge = \(rnBridge)") 

    //2. actually send the event through the eventDispatcher 
    rnBridge?.eventDispatcher().sendAppEvent(withName: "test", body: "testBody data!!!") 
    } 
} 

trong AppDelegate.h đặt (bổ sung vào mã đó là đã có trong tập tin)

#import "YourProjectsBridgingHeaderToMakeThisCodeAvailableInSwift.h" //replace this with your actual header you created when creating a swift file (google it if you dont know how to bridge swift to objective c) 

@interface PublicBridgeHelper: NSObject 
    -(RCTBridge*)getBridge; 
@end 

trong AppDelegate.m đặt (ngoài mã đó là đã có trong tập tin)

#import <React/RCTRootView.h> 

RCTBridge *rnBridgeFromRootView; 

@implementation PublicBridgeHelper //this is created to SIMPLY return rnBridgeFromRootView defined above over to my Swift class when actually sending the event to javascript that defines a react native Component 
-(RCTBridge*)getBridge { 
    NSLog(@"rnBridgeFromRootView = @%@", rnBridgeFromRootView); 
    return rnBridgeFromRootView; 
} 

quan trọng - cũng đảm bảo để thêm l sau ine mã để C Mục tiêu .h của cầu nối tiêu đề để làm PublicBridgeHelper định nghĩa này có sẵn để được sử dụng trong mã .swift

#import "AppDelegate.h" 

cuối cùng,

nay đến cho bạn thấy làm thế nào để thiết lập biến rnBridgeFromRootView sử dụng trong AppDelegate.m (mà được trở lại và sử dụng trong mã .swift ngay trước khi gửi sự kiện để javascript)

mở AppDelegate.m và trong cơ thể phương pháp

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... } 

bao gồm những điều sau sau dòng mã khởi tạo rootView biến

tức làsau khi dòng đó có thể trông giống như

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"YourProjecNameProbably" initialProperties:nil launchOptions:launchOptions]; 

add:

rnBridgeFromRootView = rootView.bridge //set the bridge to be exposed and returned later and used by the swift class 

Bây giờ để giải thích phần publicBridgeHelperInstance.getBridge() đó là trong file .swift

publicBridgeHelper là một thể hiện của một lớp c khách quan mà cho phép khả năng lớp học nhanh chóng có được tham chiếu đến cây cầu bản địa phản ứng

Nếu bạn vẫn gặp sự cố khi hiểu g câu trả lời của tôi sau khi đọc bài viết này tôi đã thực hiện một video qua nó và bạn có thể xem nó ở đây:

https://www.youtube.com/watch?v=GZj-Vm9cQIg&t=9s

+0

Tại sao bạn sẽ trộn một appdelegate Objective-C với mã nhanh chóng? –

+0

vì tôi cần nó để hiển thị rootView.bridge (tức là biến cầu) @thibautnoah đến các phần khác trong mã –

+0

bạn có thể sử dụng phiên bản .swift của ứng dụng ủy nhiệm bằng cách điều chỉnh mã tôi đã sử dụng trong AppDelegate.m nhưng từ những gì tôi nhớ, trong Swift nó đã cho tôi những vấn đề trong ngôn ngữ đó với các phương pháp họ đang sử dụng để cho phép tôi có được cây cầu (nhưng nó đã được một thời gian kể từ khi tôi nhìn vào nó) –

Các vấn đề liên quan