react-native: (Android) crash on TextInput onKeyPress when inputting an emoji via auto-complete
On 0.53.0 and later, including 0.54.2, if I input an emoji into a TextInput via auto-complete, the app crashes.
I’ve tracked down the root cause; I’ll put more details in a follow-up comment.
Environment
Environment:
OS: macOS High Sierra 10.13.3
Node: 9.7.1
Yarn: 1.5.1
npm: 5.6.0
Watchman: 4.9.0
Xcode: Xcode 9.2 Build version 9C40b
Android Studio: Not Found
Packages: (wanted => installed)
react: 16.2.0 => 16.2.0
react-native: 0.53.3 => 0.53.3
Expected Behavior
No crash!
Actual Behavior
Crash stack:
Error calling RCTEventEmitter.receiveEvent
Failed to create Value from JSON:
run
NativeRunnable.java
handleCallback
Handler.java:790
dispatchMessage
Handler.java:99
dispatchMessage
MessageQueueThreadHandler.java:31
loop
Looper.java:164
run
MessageQueueThreadImpl.java:194
run
Thread.java:764
Steps to Reproduce
Fortunately, this repros with the example project from https://github.com/facebook/react-native/issues/18262 .
- Clone and run this repo https://github.com/lxcid/ReactNative-AndroidKeyPress
- Make sure you have an Android device attached for debugging.
- react-native run-android
- select the TextInput
- type ‘potato’
- tap the potato emoji that shows up in autocomplete.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 9
- Comments: 33 (11 by maintainers)
Commits related to this issue
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to facebook/react-native by joshjhargreaves 6 years ago
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to macdoum1/react-native by joshjhargreaves 6 years ago
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to expo/react-native by joshjhargreaves 6 years ago
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to expo/react-native by joshjhargreaves 6 years ago
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to triggr/react-native by joshjhargreaves 6 years ago
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to triggr/react-native by joshjhargreaves 6 years ago
- Disable onKeyPress logic when handler not defined Summary: <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when th... — committed to darabi/react-native by joshjhargreaves 6 years ago
- "React Native sync for revisions b5c6dd2...a437f3ff3" Summary: # Please include the following changelog as your Diff Summary: This sync includes the following changes: - **[a437f3ff3](https://github.... — committed to facebook/react-native by rickhanlonii 4 years ago
Are there any updates on this issue? Thanks
So the "Failed to create value from JSON: " exception is thrown from: https://github.com/facebook/react-native/blob/0ee502d1254b828efb119cc06bcd213c3d843269/ReactCommon/jschelpers/Value.cpp#L74 (i.e., it’s trying to parse JSON from an empty string)
Debugging this code, this is called from: https://github.com/facebook/react-native/blob/0ee502d1254b828efb119cc06bcd213c3d843269/ReactCommon/jschelpers/Value.cpp#L98
The conversion to JSON produces the string:
(I’m not 100% sure if the �, which is supposed to be the potato emoji, is messed up because of the JSON conversion messing up or my debugging output.)
It is the
String(ctx, json.c_str())
conversion that is failing and returning an empty string. This leads to the line https://github.com/facebook/react-native/blob/0ee502d1254b828efb119cc06bcd213c3d843269/ReactCommon/jschelpers/Value.h#L32so it looks like
JSC_JSStringCreateWithUTF8CString
is having problems with the emoji character.@joshyhargreaves correction - it does appear to be auto-complete related here too - the original reproduction I was given was when typing something like
@mention hiya😀
, and seeminglyhiya😀
or just😀
wasn’t enough to trigger it. I’ve noticed thata hiya😀
will trigger the bug and it’s to do with autocomplete turning that intoa Hiya😀
(or@mention Hiya😀
for the previous example). Not really sure why it’s trying to auto-complete to the capitalised version of the word without it being the start of a sentence but it looks like there’s a company called Hiya so maybe that’s ended up in Google’s dictionary. With typinghiya😀
the output is actuallyHiya😀
due to text input sentence auto-capitalisation so the auto-complete isn’t triggered in that case, hence no crash.This was definitely winning weird unexplained bug of the month before I found this issue report, so thanks @akalin-keybase 👍
@kevinkevw, stupid question, but are you building react native from source for Android?
@nickofthyme yes you are correct.
I haven’t had any time to fix the route cause of the issues, the logic behind this is the route cause of the issue: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java#L102. When the cursor moves forward, the character behind the cursor is taken, as it deemed to be the character that has been pressed. I believe that
TextInput#getText
returns an Editable. I will have to investigate as I am unfamiliar with unicode support in Java, but on first impressions I do know that the unicode spec does support the combination of different unicode/emoji symbols to encode other emojis.@joshyhargreaves @akalin-keybase I think we’ve hit this issue here although not with autocomplete, seems just using the emoji keyboard does the trick and causes a crash with the
Failed to create Value from JSON
error.Can only replicate if the app is running on-device, and only so far with the stock android keyboard. Swiftkey and Samsung keyboard seem to be immune, as does any keyboard if the app is running in the Chrome devtools debugger.
@akalin-keybase @hramos I opened a PR to disable the
onKeyPress
logic, any thoughts and comments on that would be great 💯.I’m also going to have a look into the onKeyPress logic, it looks like the logic itself doesn’t work particularly well with unicode characters as it assumes key’s pressed can only have a width of 1. The potato emoji, as per the character string is encoded in java as ‘\uD83E\uDD54’ which results in two characters in the text input, and the key emitted will be the second of those two (\uDD54). There may be something wrong with the value conversion itself, but it’s never been an issue for the
onChangeText
callback.