facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.04k stars 24.32k forks source link

React Native - IOS Custom Keyboard Crashes When Memory limit of 48MB exceeds #31910

Closed rmotwani33 closed 7 months ago

rmotwani33 commented 3 years ago

Description

I have created a custom keyboard(Native) that can be selected from the input methods and can be used in any App. This keyboard works perfectly for React-Native Android App but not works in IOS When I open the App keyboard doesn't appear in the input methods list.

Here are some points to be noted:-

  1. The keyboard Appears in IOS Setting->general->keyboard->QURP keyboard

Skype_Picture_2021_07_27T12_07_40_288Z

  1. When we select from the keyboard list its doest show up

React Native version:

"react-native": "0.63.2"

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

1.Keyboard crashes due to memory limit in IOS 2.IOS Allows only 48 MB ram for Keyboard and Our app exhausts and can't render the keyboard.

  1. Here is the IOS custom keyboard native code

KeyboardViewController.m

#import "KeyboardViewController.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

@interface KeyboardViewController ()
  @property (nonatomic, strong) UIButton *nextKeyboardButton;
  @property (nonatomic) RCTRootView *rootView;
  @property (nonatomic) RCTBridge *bridge;
  @property (nonatomic) UIView *circleView;
@end

KeyboardViewController * keyboardViewController = nil;

@implementation KeyboardViewController

- (void)updateViewConstraints {
    [super updateViewConstraints];

    if (self.rootView) {
        NSLog(@"chaning root view dimensions");
        self.rootView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];

    CGFloat _expandedHeight = 350;
    NSLayoutConstraint *_heightConstraint =
        [NSLayoutConstraint constraintWithItem: self.view
                                   attribute: NSLayoutAttributeHeight
                                   relatedBy: NSLayoutRelationEqual
                                      toItem: nil
                                   attribute: NSLayoutAttributeNotAnAttribute
                                  multiplier: 0.0
                                    constant: _expandedHeight];
    [self.view addConstraint: _heightConstraint];

    NSLog(@"Added loading view");

    /* Custom RN View */
    self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:@{@"keyboardExtension": self}];

    NSDictionary *props = @{@"isKeyboard" : @true};
    self.rootView = [[RCTRootView alloc] initWithBridge:self.bridge
                                                     moduleName:@"RNKeyboard"
                                               initialProperties:props];
    [self.view addSubview:self.rootView];
    /* Custom RN View - end */
       [self updateViewConstraints];
    keyboardViewController = self;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  #if DEBUG
    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  #else
    return [CodePush bundleURL];
  #endif
}

- (void)viewWillLayoutSubviews
{
    self.nextKeyboardButton.hidden = !self.needsInputModeSwitchKey;
    [super viewWillLayoutSubviews];
}

- (void)textWillChange:(id<UITextInput>)textInput {
    // The app is about to change the document's contents. Perform any preparation here.
}

- (void)textDidChange:(id<UITextInput>)textInput {
    // The app has just changed the document's contents, the document context has been updated.

    UIColor *textColor = nil;
    if (self.textDocumentProxy.keyboardAppearance == UIKeyboardAppearanceDark) {
        textColor = [UIColor whiteColor];
    } else {
        textColor = [UIColor blackColor];
    }
    [self.nextKeyboardButton setTitleColor:textColor forState:UIControlStateNormal];
}

@end

KeyboardExtension.m

#import <UIKit/UIKit.h>
#import "KeyboardViewController.h"
#import <React/RCTBridge.h>

@interface TextCommunicationsModule : NSObject <RCTBridgeModule>

@end

@implementation TextCommunicationsModule

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE(TextCommunications);

RCT_EXPORT_METHOD(insertText:(NSString *)phrase)
{
  KeyboardViewController *extension = self.bridge.launchOptions[@"keyboardExtension"];
  [extension.textDocumentProxy insertText:phrase];
}

RCT_EXPORT_METHOD(advanceToNextInputMode)
{
  KeyboardViewController *extension = self.bridge.launchOptions[@"keyboardExtension"];
  [extension advanceToNextInputMode];
}

@end

Expected Results

The keyboard Should be Opened and usable for Any IOS App

safaiyeh commented 3 years ago

Hi @rmotwani33 thanks for the issue. This is a very interesting use case! I need some more context to understand it.

Does your custom keyboard utilize react native for its implementation? Or it crashes on React Native applications?

rmotwani33 commented 3 years ago

Hi, @safaiyeh Thanks for replying, Yes it will crash on our react native app as well in every IOS App,

Here I have registered components with the app and keyboard. Like this It's the beginning part of the app.

App.js

import React from 'react';
import { AppRegistry } from 'react-native';
import Keyboard from './app/screens/Keyboard';
import { name as RNFirebaseBackgroundMessage } from './app.json';

function HeadlessCheck({ isHeadless, isKeyboard }) {
  if (isKeyboard) {
    console.log('Keyboard app ==> No need to start the app');
  } else {
    console.log('Headless Check ====> ', isHeadless);
    if (isHeadless) {
      // App has been launched in the background by iOS, ignore
      return null;
    }

    const App = require('./app/index').default;
    require('react-native-gesture-handler');
    import('react-native-screens')
      .then((module) => {
        // Do something with the module.
        module.enableScreens();
      });

    import('@react-native-firebase/messaging')
      .then((module) => {
        console.log('module ==> ', module);
        module.default().setBackgroundMessageHandler(async (remoteMessage) => {
          console.log('Message handled in the background!', remoteMessage);
        });
      });

    console.log('App ==> ', App);
    return <App />;
  }
}

AppRegistry.registerComponent(RNFirebaseBackgroundMessage, () => HeadlessCheck);

AppRegistry.registerComponent('RNKeyboard', () => Keyboard);

@safaiyeh One more thing I want to tell you, In IOS I think the problem is with memory it's consuming a lot of memory and then crash.

rmotwani33 commented 3 years ago

Hi, @safaiyeh Thanks for replying, Yes it will crash on our react native app as well in every IOS App,

Here I have registered components with the app and keyboard. Like this It's the beginning part of the app.

App.js

import React from 'react';
import { AppRegistry } from 'react-native';
import Keyboard from './app/screens/Keyboard';
import { name as RNFirebaseBackgroundMessage } from './app.json';

function HeadlessCheck({ isHeadless, isKeyboard }) {
  if (isKeyboard) {
    console.log('Keyboard app ==> No need to start the app');
  } else {
    console.log('Headless Check ====> ', isHeadless);
    if (isHeadless) {
      // App has been launched in the background by iOS, ignore
      return null;
    }

    const App = require('./app/index').default;
    require('react-native-gesture-handler');
    import('react-native-screens')
      .then((module) => {
        // Do something with the module.
        module.enableScreens();
      });

    import('@react-native-firebase/messaging')
      .then((module) => {
        console.log('module ==> ', module);
        module.default().setBackgroundMessageHandler(async (remoteMessage) => {
          console.log('Message handled in the background!', remoteMessage);
        });
      });

    console.log('App ==> ', App);
    return <App />;
  }
}

AppRegistry.registerComponent(RNFirebaseBackgroundMessage, () => HeadlessCheck);

AppRegistry.registerComponent('RNKeyboard', () => Keyboard);

@safaiyeh One more thing I want to tell you, In IOS I think the problem is with memory it's consuming a lot of memory and then crash.

@safaiyeh Any Update regarding the above issue please?

github-actions[bot] commented 7 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] commented 7 months ago

This issue was closed because it has been stalled for 7 days with no activity.