2016-05-10 16 views
16

Stiamo passando una conversione graduale della mia applicazione in React Native. E continuo a riscontrare problemi con Dependency Injection in React Native su iOS.Iniezione dipendenza in moduli React Native

Ho alcuni servizi nella mia app che mi piacerebbe utilizzare in un modulo nativo. Attualmente vengono iniettati tramite Typhoon e tutto funziona perfettamente.

Tuttavia, la reazione nativa stessa inizializza e mantiene qualsiasi modulo nativo come singleton. Questo mi impedisce di far inizializzare i Typhoon e quindi non posso iniettare loro dipendenza.

Cosa si può fare? Creare l'RCTBridge da solo è un'opzione, ma si sente molto a basso livello e, comunque, è necessario capire come iniettarlo in UIView in primo luogo.

risposta

10

Non sono esattamente sicuro del motivo per cui la tua domanda non ha ricevuto più voti positivi; Io stesso stavo cercando di rispondere alla stessa domanda e pensavo di dover saltare e rispondere alla mia prima domanda StackOverflow!

Scavando intorno allo RCTBridge class ha fornito la risposta. Quello che dovete fare è inizializzare manualmente un RCTBridge con un'istanza di una classe che implementa l'RCTBridgeProtocol (e soprattutto il metodo 'extraModulesForBridge'; si potrebbe anche implementare questo protocollo nella tua View Controller, se si voleva

// Initialise a class that implements RCTBridgeDelegate 
// Be warned, RCTBridge won't store a strong reference to your delegate. 
// You should there store this delegate as a property of your initialising class, or implement the protocol in the View Controller itself. 
id<RCTBridgeDelegate> moduleInitialiser = [[classThatImplementsRCTBridgeDelegate alloc] init]; 

// Create a RCTBridge instance 
// (you may store this in a static context if you wish to use with other RCTViews you might initialise. 
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil]; 

// Initialise an RCTRootView 
RCTRootView *rootView = [[RCTRootView alloc] 
        initWithBridge:bridge 
         moduleName:kModuleName 
        initialProperties:nil]; 

// Note that your class that implements RCTBridgeDelegate SHOULD implement the following methods and it might look something like this. 

// This will return the location of our Bundle 
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 
{ 
    return [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"]; 
} 

// Importantly, this is the method we need to implement to answer this question 
// We must return an array of initialised Modules 
// Be warned, I am writing this off of the top of my head, so excuse any syntax errors there might be! 
- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge 
{ 
    return @[[OurNativeModule alloc] initWithCustomInitialiser:customDependency]]; 
} 
.

Edit: ho aggiunto questo alla documentazione React-native https://facebook.github.io/react-native/docs/native-modules-ios.html#dependency-injection

+0

realtà ho scoperto questo per conto mio, ma non riusciva a trovare un buon modo per creare RCTModules (credo che fosse RCTModule, era qualche tempo fa) durante l'utilizzo di Swift, dal momento che tutta la nostra applicazione è Swift Based . Tuttavia, potrei rivisitare questo e usare solo l'obiettivo C per l'impianto idraulico e scrivere il modulo nativo attuale in modo rapido. Hai funzionato? – Rubys

+0

Esiste la possibilità di sostituire moduli nativi standard come DatePickerIOS con la mia implementazione che utilizza qualcosa come API privata per cambiare i colori di selezione? – pinguinjkeke

2

il codice di cui sopra funziona bene Ecco la versione Swift 4 del codice

@objc(RNModuleInitialiser) 
final class RNModuleInitialiser: NSObject { 

    //Inject your dependencies here 
    init() { 

    } 

} 

extension RNModuleInitialiser: RCTBridgeDelegate { 

    func sourceURL(for bridge: RCTBridge!) -> URL! { 
     return URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")! 
    } 

    func extraModules(for bridge: RCTBridge!) -> [RCTBridgeModule]! { 

     var extraModules = [RCTBridgeModule]() 

     //Initialise the modules here using the dependencies injected above 

     return extraModules 
    } 

} 

Quando si inizializza il ponte, passare la m... oduleInitialiser:

//Make sure to hold the strong reference to the moduleInitaliser 

self.moduleInitialiser = RNModuleInitialiser() 
self.bridge = RCTBridge(delegate: self.moduleInitialiser, launchOptions: nil)