Reputation: 51
I'm trying to create a native (iOS) module for a React Native app using Swift. I want to expose a method on the module that returns a promise, using functions of type RCTPromiseResolveBlock
and RCTPromiseRejectBlock
, both of which are declared in React Native's RCTBridgeModule.h
header. However, my build fails with the message "Use of undeclared type..." for both of these types.
I had already created a bridging header (automatically using Xcode) for another purpose, so I believe importing React/RCTBridgeModule.h
is all that I'd need to supply the types mentioned above. Presumably I've misconfigured something, as this doesn't fix the issue. I've tried setting up a fresh project and everything works as expected there, but I can't seem to find a difference that would cause my project's build to fail.
Some relevant configuration details:
<ProjectName>-Bridging-Header.h
and stored in my source directory. I moved it around to confirm that Xcode is finding it (the build fails differently when it's not in the right place).#import <React/RCTBridgeModule.h>
<ProjectName>-Bridging-Header.h
is configured as the "Objective-C Bridging Header"react-native link
and one using a Git submodule)node_modules
and deleting Xcode derived data, all to no effect.Is my project misconfigured or have I otherwise missed something important?
Upvotes: 5
Views: 6263
Reputation: 28539
This tutorial is pretty good at explaining how to set up a native module using Swift. It breaks everything down into steps and it is quite easy to follow.
https://teabreak.e-spres-oh.com/swift-in-react-native-the-ultimate-guide-part-1-modules-9bb8d054db03
Clearly it is step 6 that you are looking to do.
Here is a code example. It is very similar to what is done in the above link. Your bridging header should look like this:
// <ProjectName>-Bridging-Header.h
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
You should have files named ModuleName.m
and ModuleName.swift
.
// ModuleName.m
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
@interface RCT_EXTERN_MODULE(ModuleName, NSObject)
// this is how we expose the promise to the javascript side.
RCT_EXTERN_METHOD(functionWithPromise: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject)
@end
// ModuleName.swift
@objc(ModuleName)
class ModuleName: NSObject {
@objc
func constantsToExport() -> [AnyHashable : Any]! {
return ["projectName": "ModuleName"]
}
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
@objc
func functionWithPromise(
_ resolve: RCTPromiseResolveBlock,
rejecter reject: RCTPromiseRejectBlock
) -> Void {
if (//something bad happens) {
let error = NSError(domain: "", code: 200, userInfo: nil)
reject("ERROR_FOUND", "failure", error)
} else {
resolve("success")
}
}
}
Then on the Javascript side you can access it like this:
import { NativeModules } from 'react-native'
NativeModules.Counter.functionWithPromise()
.then(res => console.log(res))
.catch(e => console.log(e.message, e.code))
Upvotes: 7