Android ReactActivity Destroy Prevents Successful OnActivityResult Calls
まだ誰も着手していません。
- 主要言語
- C++
- スター
- 127k
- フォーク
- 25.3k
- 平均マージ
- 1日 23時間
- マージ済み PR(30日)
- 4
説明
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:
ReactActivity#onCreateReactActivityDelegate#onCreateReactActivityDelegate#loadAppReactDelegate#loadAppReactRootView#startReactApplicationReactInstanceManager#createReactContextInBackgroundReactInstanceManager#recreateReactContextInBackgroundInnerReactInstanceManager#recreateReactContextInBackgroundFromBundleLoaderReactInstanceManager#recreateReactContextInBackgroundReactInstanceManager#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
- Clone
- https://github.com/zsweigart/react-native-crash
- cd into the directory and run
react-native run-android - On your device or emulator go to developer options
- Turn
Do Not Keep ActivitiestoOn - Set
Background Process LimittoNo background processes - Click
Open Activity - 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 runadb shell am kill com.react_native_crashwhich 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. - Next run
adb shell am start -n com.react_native_crash/.RedirectActivity -d "redirect://crash" - 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:
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
記載されている ReactActivity と ReactActivityDelegate の起動フローから始め、続いて setupReactContext および runCreateReactContextOnNewThread と併せて ReactInstanceManager#onActivityResult を調べます。リンク先の react-native-crash プロジェクトと adb コマンドを使ってこのケースを再現します。Return Result の後にコンソールが RESULT と Completed を出力し、callback が JavaScript に到達したことを示せば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- android, java, react-native
- 領域
- mobile-dev
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 静か
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 52/100