I'm trying to use gRPC at React Native. First, I was able to setup my gRPC module with Objective-C. Next, I made a native module for that gRPC module.
The gRPC module is quite simple.
rpc CheckEmail(EmailCheckRequest) returns (EmailCheckResponse) {}
message EmailCheckRequest {
string email = 1;
}
message EmailCheckResponse {
common.RetCode ret = 1;
}
As you can see, there is one input parameter(email address) and returns a "Return Code".
I checked how to make a native module at .html and it shows how to make a module with a parameter or a module with a return value, but it does not explain how to make one with both.
Here are the examples.
Module with a parameter
RCT_EXPORT_METHOD(addEvent:(NSString *)name)
{
RCTLogInfo(@"Pretending to create an event %@", name);
}
Module with a return value(Actually, with Promise)
RCT_REMAP_METHOD(findEvents,
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *events = ...
if (events) {
resolve(events);
} else {
NSError *error = ...
reject(@"no_events", @"There were no events", error);
}
}
Anyway, based on this, I made my own code like this.
RCT_REMAP_METHOD(checkEmail: (NSString *)email, resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
/* ... */
}
And the react-native side javascript code is like this. var NetworkService = NativeModules.NetworkService; var ret = NetworkService.checkEmail('[email protected]');
There was no compile error, but while running the app, XCode returns this runtime error at RCT_REMAP_METHOD line "com.facebook.React.JavaScript (11):EXC_BAD_ACCESS(code=1, address=0x88)
It looks like there is something wrong with RCT_REMAP_METHOD macro, but don't know Objective-C details and don't know how to use marco.
If there is someone who knows how to use RCT_REMAP_METHOD macro to export a module with a parameter and a return value or if there is something wrong with my code, please let me know.
Additional Finding I followed the definition of RCT_REMAP_METHOD and it seems that it is okay to use RCT_EXPORT_METHOD instead, because EXPORT is redefinition of REMAP and there is an example of Promises with EXPORT, but not sure whether it is the right way to do this.
* ## Promises
*
* Bridge modules can also define methods that are exported to JavaScript as
* methods that return a Promise, and are compatible with JS async functions.
*
* Declare the last two parameters of your native method to be a resolver block
* and a rejecter block. The resolver block must precede the rejecter block.
*
* For example:
*
* RCT_EXPORT_METHOD(doSomethingAsync:(NSString *)aString
* resolver:(RCTPromiseResolveBlock)resolve
* rejecter:(RCTPromiseRejectBlock)reject
* { ... }
*
* Calling `NativeModules.ModuleName.doSomethingAsync(aString)` from
* JavaScript will return a promise that is resolved or rejected when your
* native method implementation calls the respective block.
*
*/
I'm trying to use gRPC at React Native. First, I was able to setup my gRPC module with Objective-C. Next, I made a native module for that gRPC module.
The gRPC module is quite simple.
rpc CheckEmail(EmailCheckRequest) returns (EmailCheckResponse) {}
message EmailCheckRequest {
string email = 1;
}
message EmailCheckResponse {
common.RetCode ret = 1;
}
As you can see, there is one input parameter(email address) and returns a "Return Code".
I checked how to make a native module at https://facebook.github.io/react-native/docs/native-modules-ios.html and it shows how to make a module with a parameter or a module with a return value, but it does not explain how to make one with both.
Here are the examples.
Module with a parameter
RCT_EXPORT_METHOD(addEvent:(NSString *)name)
{
RCTLogInfo(@"Pretending to create an event %@", name);
}
Module with a return value(Actually, with Promise)
RCT_REMAP_METHOD(findEvents,
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *events = ...
if (events) {
resolve(events);
} else {
NSError *error = ...
reject(@"no_events", @"There were no events", error);
}
}
Anyway, based on this, I made my own code like this.
RCT_REMAP_METHOD(checkEmail: (NSString *)email, resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
/* ... */
}
And the react-native side javascript code is like this. var NetworkService = NativeModules.NetworkService; var ret = NetworkService.checkEmail('[email protected]');
There was no compile error, but while running the app, XCode returns this runtime error at RCT_REMAP_METHOD line "com.facebook.React.JavaScript (11):EXC_BAD_ACCESS(code=1, address=0x88)
It looks like there is something wrong with RCT_REMAP_METHOD macro, but don't know Objective-C details and don't know how to use marco.
If there is someone who knows how to use RCT_REMAP_METHOD macro to export a module with a parameter and a return value or if there is something wrong with my code, please let me know.
Additional Finding I followed the definition of RCT_REMAP_METHOD and it seems that it is okay to use RCT_EXPORT_METHOD instead, because EXPORT is redefinition of REMAP and there is an example of Promises with EXPORT, but not sure whether it is the right way to do this.
* ## Promises
*
* Bridge modules can also define methods that are exported to JavaScript as
* methods that return a Promise, and are compatible with JS async functions.
*
* Declare the last two parameters of your native method to be a resolver block
* and a rejecter block. The resolver block must precede the rejecter block.
*
* For example:
*
* RCT_EXPORT_METHOD(doSomethingAsync:(NSString *)aString
* resolver:(RCTPromiseResolveBlock)resolve
* rejecter:(RCTPromiseRejectBlock)reject
* { ... }
*
* Calling `NativeModules.ModuleName.doSomethingAsync(aString)` from
* JavaScript will return a promise that is resolved or rejected when your
* native method implementation calls the respective block.
*
*/
Share
Improve this question
edited Jul 16, 2017 at 0:30
Spike
asked Jul 14, 2017 at 9:17
SpikeSpike
1931 gold badge2 silver badges7 bronze badges
2 Answers
Reset to default 14RCT_EXPORT_METHOD
is just to remap
the js function to native function. This is useful when multiple native methods are the same up to the first colon and would have conflicting JavaScript names.
As the define RCT_REMAP_METHOD(js_name, method)
, the js_name
means the function called from the js code, method
means the native function name.
So if you want to export a method with a parameter (or more), you can do like so:
// Bridge.m
RCT_EXPORT_MODULE(Bridge)
RCT_REMAP_METHOD(findEvents,
type:(NSString *)type
params:(NSDictionary *)params
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ ... }
Then from the js code, call the function like this:
const Bridge = NativeModules.Bridge;
class App extends Component {
asnyc _buttonPress() {
try {
let result = await Bridge.findEvents("type", {"key": "value"});
// handle the result
} catch(e) {
// handle the error
}
}
}
Make sure the
RCTPromiseResolveBlock
andRCTPromiseRejectBlock
are the last two parameters.
As I mentioned at the additional finding part, I was able to export a module with a parameter and a return value with RCT_EXPORT_METHOD.
RCT_EXPORT_METHOD(checkEmail: (NSString *)email
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
/* ... */
}
In this way, I was able to export "checkEmail".
Javascript : NativeModules.ModuleName.checkEmail(email);
I have no Objective-C background knowledge, so even if it works in this way, if there is something wrong with my code, please let me know. =)