【问题标题】:React Native Native Module looping call until crash on iOSReact Native Native Module 循环调用直到在 iOS 上崩溃
【发布时间】:2022-01-08 03:25:24
【问题描述】:

我正在尝试在 iOS 上的 React Native 中构建一个 gRPC 客户端。

对于上下文:不直接支持 gRPC 的 React Native 必须从 Swift 中调用一个自定义的 Native Module,这使得 gRPC 调用并返回值。

gRPC 服务器是一个本地编译的 goLang 模块,它使用 http2server 模块。我没有编写 gRPC 服务器,所以我无法更改它的代码。

React Native 方法似乎在循环执行原生 gRPC 客户端调用,导致 Golang 的 http2Server 模块崩溃。

此 gRPC 客户端调用是从按钮 onPress() 事件调用的,而不是从循环调用的。我尝试将 gRPC 调用封装在超时测试中,以防止调用过快。

我的 Native 模块有一个如下所示的导出函数:

@objc(SwiftNativeGrpcClient) class SwiftNativeGrpcClient: NSObject {
  // ...
  @objc func swiftGetGrpcTest(
    _ resolve: RCTPromiseResolveBlock,
    rejecter reject: RCTPromiseRejectBlock
  ) {
    print("SwiftNativeGrpcClient.swiftGetGrpcTest()")
    // connect to gRPC channel if necessary
    if (self.secureGrpcChannel == nil) {
      self.createSecureChannel()
    }
    // out of paranoia, don't let this call be used less than
    // once per second
    if (getMilliSecondsSinceLastCall() < 1000) {
      print("Method called to soon.")
      reject("0", "Method called too soon", nil)
      return
    }
    let grpcServiceClient = Service_ServiceName(channel: self.secureGrpcChannel!)
    let testRequest: Service_TestRequest = Service_TestRequest()
    // Service_TestResponse should contain a String:
    // "gRPC response success"
    let testResponse: Service_TestResponse
    let testCall = grpcServiceClient.getTest(testRequest)
    do {
        try testResponse = testCall.response.wait()
        print(testResponse)
    } catch {        ​
      ​print("RPC method 'getInfo' failed \(error)")
      ​return
    ​}
    // update the last call time to ensure this isn't being called
    // more than once per second
    self.lastCallTime = DispatchTime.now()
    resolve(getInfoResponse)
  }
  // ...
}

我的 React Native 像这样调用原生模块:

const { SwiftNativeGrpcClient } = NativeModules;

export default function App() {
  const nativeGrpcClient = useRef(SwiftNativeGrpcClient)
  const [lastCallTime, setLastCallTime] = useState(new Date())

  const rnGetGrpcTest = async () => {
    try {
      const currentTime = new Date()
      console.log(`lastCallTime: ${lastCallTime}`)
      console.log(`currentTime: ${currentTime}`)
      const timeDiff = currentTime - lastCallTime
      console.log(`timeDiff: ${timeDiff} ms`)
      // Just checking... don't let this method
      // be executed more than once per second
      if (timeDiff > 1000) {
        await nativeGrpcClient.current.swiftGetGrpcTest()
      }
    } catch (error) {
      console.error(error.message)
    }
    setLastCallTime(currentTime)
  }
  // ...
}

Xcode 输出如下所示 ​

  1. 看起来 gRPC 客户端正在对 gRPC 服务器进行多次调用。在崩溃之前,您会看到 React Native 模块发射器发出大约 20 次相同的响应
2021-12-01 15:23:56.400068+0200 testApp[13091:123303] [javascript] { output: 'SwiftNativeGrpcClient.swiftGetGrpcTest()\n' }

2021-12-01 15:23:58.698908+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.699576+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.700075+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.700606+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.701067+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.701596+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.702036+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.702726+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.704172+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.704766+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.705121+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.705497+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.705833+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.715472+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
panic: 2021-12-01 15:23:58.715856+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.716342+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.716751+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.717020+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.717247+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.717510+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.718216+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
close of closed channel

goroutine 24507 [2021-12-01 15:23:58.718544+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
running]:
2021-12-01 15:23:58.718827+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.719167+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
  1. Golang 的 http2Server 在通过原生 Swift 模块向 React Native 返回响应后,在 handlePing() 方法期间崩溃。似乎 gRPC 连接已关闭,然后再次尝试关闭,但 http2server 无法正常处理

这是 Xcode 控制台日志:

2021-12-01 15:23:58.717247+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.717510+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.718216+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
close of closed channel
goroutine 24507 [2021-12-01 15:23:58.718544+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
running]:
goroutine 24507 [2021-12-01 15:23:58.718544+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
running]:
2021-12-01 15:23:58.718827+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.719167+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
google.golang.org/grpc/internal/transport.(*http2Server).handlePing(0xc00007a1c0, 0xc003c08090)
    google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/internal/transport/http2_server.go:680 +0x6d
google.golang.org/grpc/internal/transport.(*http2Server).HandleStreams(0xc00015d800, 0xc0029d0f68, 0x10a742005)
    google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/internal/transport/http2_server.go:494 +0x31f
google.golang.org/grpc.(*Server).serveStreams(0xc000499860, {0x10b916390, 0xc00015d800})
    google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/server.go:742 +0x114
google.golang.org/grpc.(*Server).handleRawConn.func1()
    google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/server.go:703 +0x34
created by google.golang.org/grpc.(*Server).handleRawConn
    google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/server.go:702 +0x405
CoreSimulator 757.5 - Device: iPhone SE (2nd generation) (ECBD797A-E2B4-49F2-9DD5-BC8FB95EFACC) - Runtime: iOS 14.5 (18E182) - DeviceType: iPhone SE (2nd generation)

当我使用完全相同的 Swift 代码创建一个测试项目但没有 React Native 前端时,我没有遇到这种崩溃。 React Native 以某种方式参与了崩溃行为,可能是由于 Native Module 功能的功能?

有没有人知道如何防止这种循环发生?

【问题讨论】:

    标签: javascript ios react-native go grpc-swift


    【解决方案1】:

    如果其他人有类似的问题,

    我的问题与循环的外观无关。

    我需要在 Swift 函数结束时关闭 gRPC 通道。这可以使用defer 语句来完成:

    @objc(SwiftNativeGrpcClient) class SwiftNativeGrpcClient: NSObject {
      // ...
      @objc func swiftGetGrpcTest(
        _ resolve: RCTPromiseResolveBlock,
        rejecter reject: RCTPromiseRejectBlock
      ) {
        if (self.secureGrpcChannel == nil) {
          self.createSecureChannel()
        }
        let grpcServiceClient = Service_ServiceName(channel: self.secureGrpcChannel!)
        defer {
            // close the channel when the method exits
            try? grpcServiceClient.channel.close().wait()
        }
        let testRequest: Service_TestRequest = Service_TestRequest()
        // Service_TestResponse should contain a String:
        // "gRPC response success"
        let testResponse: Service_TestResponse
        let testCall = grpcServiceClient.getTest(testRequest)
        do {
            try testResponse = testCall.response.wait()
            print(testResponse)
            resolve(getInfoResponse)
        } catch {        ​
          ​print("RPC method failed \(error)")
          reject("0","RPC method failed: \(error)", nil)
          ​return
        ​}
        // update the last call time to ensure this isn't being called
        // more than once per second
      }
      // ...
    }
    

    循环控制台输出是由两件事的交互引起的:

    1. 我正在捕获标准输出并通过RCTEventEmitter 路由它
    2. 在事件之间没有清除缓冲区。

    所以看起来好像 RCTEventEmitter 多次收到 gRPC 成功消息。

    【讨论】:

      猜你喜欢
      • 2019-06-01
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 2019-12-30
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多