react / react/react-native

Android ReactActivity Destroy Prevents Successful OnActivityResult Calls

Đang mở
#30,277 35 bình luận 31 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Issue: Author Provided Repro Platform: Android
Ngôn ngữ chính
C++
Star
127k
Fork
25.3k
Merge trung bình
1 ngày 23 giờ
Pull request đã merge (30 ngày)
4

Mô tả

Description

If a native module opens an activity that redirects out of the application and the application is killed in the background by the Android OS, the react context is lost and the native module's activity is unable to call onActivityResult.

If the redirect from the third party app is back to the activity in the native module, the ReactActivity is not created at this point. When the native activity then sets result and finishes to return back to the ReactActivity the ReactActivity has to start up.

The React Native startup flow is:

  1. ReactActivity#onCreate
  2. ReactActivityDelegate#onCreate
  3. ReactActivityDelegate#loadApp
  4. ReactDelegate#loadApp
  5. ReactRootView#startReactApplication
  6. ReactInstanceManager#createReactContextInBackground
  7. ReactInstanceManager#recreateReactContextInBackgroundInner
  8. ReactInstanceManager#recreateReactContextInBackgroundFromBundleLoader
  9. ReactInstanceManager#recreateReactContextInBackground
  10. ReactInstanceManager#runCreateReactContextOnNewThread

At this point ReactInstanceManager#setupReactContext is called on a background thread.

Meanwhile, ReactActivity#onActivityResult is called. In the Android activity lifecycle onActivityResult is called even before onResume (for reference. The calls from ReactActivity#onActivityResult pass through a few layers and end up at ReactInstanceManager#onActivityResult which checks if the ReactContext is null

  @ThreadConfined(UI)
  public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
    ReactContext currentContext = getCurrentReactContext();
    if (currentContext != null) {
      currentContext.onActivityResult(activity, requestCode, resultCode, data);
    }
  }

Because the context is being built on a background thread there is no guarantee that currentContext will be initialized at this point. Furthermore ReactInstanceManager#createReactContext is a fairly intensive function so it is actually very likely that currentContext is null.

This means that ReactContext#onActivityResult is not called and therefore, the data cannot be passed back to the ActivityEventListener which in my sample is the ReactContextBaseJavaModule.

React Native version:

System:
    OS: macOS 10.15.7
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 118.90 MB / 32.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 13.14.0 - ~/.nvm/versions/node/v13.14.0/bin/node
    Yarn: 1.22.5 - /usr/local/bin/yarn
    npm: 6.14.4 - ~/.nvm/versions/node/v13.14.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.3 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK:
      API Levels: 19, 23, 26, 27, 28, 29
      Build Tools: 27.0.3, 28.0.3, 29.0.0, 29.0.1, 29.0.2
      System Images: android-21 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom, android-26 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-29 | Google Play Intel x86 Atom, android-Q | Android TV Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6626763
    Xcode: 11.6/11E708 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_265 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.13.1 => 16.13.1 
    react-native: 0.63.3 => 0.63.3 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

  1. Clone
  2. https://github.com/zsweigart/react-native-crash
  3. cd into the directory and run react-native run-android
  4. On your device or emulator go to developer options
  5. Turn Do Not Keep Activities to On
  6. Set Background Process Limit to No background processes
  7. Click Open Activity
  8. Click Go to Web -> This should kill the original process in the background due to your developer settings; however, on some emulators I have noticed it does not. One way to guarantee this is to run adb shell am kill com.react_native_crash which will simulate a system process kill. Note you cannot kill the process by swiping it away because the OS will lose the information about the backstack.
  9. Next run adb shell am start -n com.react_native_crash/.RedirectActivity -d "redirect://crash"
  10. Click Return Result

Expected Results

After these steps in the console you should see

 LOG      RESULT
 LOG      Completed

which would indicate the onActivityResult was called properly and the callback to the js code was executed.

Snack, code example, screenshot, or link to a repository:

https://github.com/zsweigart/react-native-crash

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với luồng khởi động ReactActivity và ReactActivityDelegate được liệt kê, sau đó kiểm tra ReactInstanceManager#onActivityResult cùng với setupReactContext và runCreateReactContextOnNewThread. Tái hiện trường hợp này bằng dự án react-native-crash được liên kết và các lệnh adb; hoàn tất khi console hiển thị RESULT và Completed sau Return Result, cho thấy callback đã tới JavaScript.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
android, java, react-native
Lĩnh vực
mobile-dev
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
52/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.