我需要在我的 React Native iOS 应用程序上使用来自 javascript 代码的自定义原生 fetch 函数,它必须是异步的,并且与标准函数一样工作。我想用 React Native JSI 来实现它,那么如何将异步函数暴露给 javascript?
问问题
92 次
1 回答
1
要将异步函数从本机公开到 javascript,您可以使用Promise
React Native 运行时中的对象并使用其构造函数用您的代码构建 Promise。例如,“nativeFetch”函数的实现有NSURLSession
:
AppDelegate.mm
#include <jsi/jsi.h>
#import <React/RCTBridge+Private.h>
using namespace facebook::jsi;
using namespace std;
void installNativeFetch(Runtime& runtime) {
auto nativeFetch = Function::createFromHostFunction(runtime,
PropNameID::forAscii(runtime, "nativeFetch"),
1,
[](Runtime &runtime, const Value &thisValue, const Value *args, size_t count) -> Value {
const string strURL = args[0].asString(runtime).utf8(runtime);
// Get global Promise
auto promise = runtime.global().getPropertyAsFunction(runtime, "Promise");
return promise.callAsConstructor(runtime, Function::createFromHostFunction(runtime,
PropNameID::forAscii(runtime, "executor"),
2,
[strURL](Runtime &runtime, const Value &thisValue, const Value *args, size_t) -> Value {
auto resolve = make_shared<Value>(runtime, args[0]);
auto reject = make_shared<Value>(runtime, args[1]);
NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:strURL.c_str()]];
NSURLSessionDataTask* task = [NSURLSession.sharedSession dataTaskWithURL:url completionHandler:^(NSData* data, NSURLResponse* response, NSError* error) {
if (error != nil) {
// Reject
auto value = Value(runtime, String::createFromUtf8(runtime, error.localizedDescription.UTF8String));
reject->asObject(runtime).asFunction(runtime).call(runtime, move(value));
}
else {
auto result = Object(runtime);
int statusCode = (int)((NSHTTPURLResponse*)response).statusCode;
result.setProperty(runtime, "statusCode", statusCode);
result.setProperty(runtime, "statusText", String::createFromUtf8(runtime, [NSHTTPURLResponse localizedStringForStatusCode:statusCode].UTF8String));
// Resolve
resolve->asObject(runtime).asFunction(runtime).call(runtime, move(result));
}
}];
[task resume];
return {};
}));
});
// Bind our function with the javascript runtime global object
runtime.global().setProperty(runtime, "nativeFetch", nativeFetch);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
...
// Runtime notification
[NSNotificationCenter.defaultCenter addObserverForName:RCTJavaScriptDidLoadNotification object:nil queue:nil
usingBlock:^(NSNotification* notification) {
// Get runtime
RCTCxxBridge* cxxbridge = (RCTCxxBridge*)notification.userInfo[@"bridge"];
if (cxxbridge.runtime) {
Runtime& runtime = *(Runtime*)cxxbridge.runtime;
installNativeFetch(runtime);
}
}];
return YES;
}
应用程序.js
async function get(url) {
try {
const result = await nativeFetch(url);
console.log(result);
}
catch (e) {
console.log("Error: " + e);
}
}
...
get('https://unknown');
get('https://google.com');
输出:
{ statusCode: 200, statusText: 'no error' }
Error: A server with the specified hostname could not be found.
注意:由于示例使用 JSI 进行同步本地方法访问,远程调试(例如使用 Chrome)不再可能。相反,您应该使用 Flipper 来调试您的 JS 代码。
于 2022-01-27T14:22:05.210 回答