Fix an issue that deleting an emoji may crash the app (#34508)

diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm
index 0e2c656..2d33fb9 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm
@@ -7,6 +7,8 @@
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
 
+#include "unicode/uchar.h"
+
 #include "flutter/fml/logging.h"
 #include "flutter/fml/platform/darwin/string_range_sanitization.h"
 
@@ -1896,6 +1898,22 @@
     NSRange oldRange = ((FlutterTextRange*)oldSelectedRange).range;
     if (oldRange.location > 0) {
       NSRange newRange = NSMakeRange(oldRange.location - 1, 1);
+
+      // We should check if the last character is a part of emoji.
+      // If so, we must delete the entire emoji to prevent the text from being malformed.
+      NSRange charRange = fml::RangeForCharacterAtIndex(self.text, oldRange.location - 1);
+      UChar32 codePoint;
+      BOOL gotCodePoint = [self.text getBytes:&codePoint
+                                    maxLength:sizeof(codePoint)
+                                   usedLength:NULL
+                                     encoding:NSUTF32StringEncoding
+                                      options:kNilOptions
+                                        range:charRange
+                               remainingRange:NULL];
+      if (gotCodePoint && u_hasBinaryProperty(codePoint, UCHAR_EMOJI)) {
+        newRange = NSMakeRange(charRange.location, oldRange.location - charRange.location);
+      }
+
       _selectedTextRange = [[FlutterTextRange rangeWithNSRange:newRange] copy];
       [oldSelectedRange release];
     }
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm
index bd656cb..bec7028 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm
@@ -406,6 +406,41 @@
   XCTAssertEqualObjects(substring, @"bbbbaaaabbbbaaaa");
 }
 
+- (void)testDeletingBackward {
+  NSDictionary* config = self.mutableTemplateCopy;
+  [self setClientId:123 configuration:config];
+  NSArray<FlutterTextInputView*>* inputFields = self.installedInputViews;
+  FlutterTextInputView* inputView = inputFields[0];
+
+  [inputView insertText:@"αžΉπŸ˜€ text πŸ₯°πŸ‘¨‍πŸ‘©‍πŸ‘§‍πŸ‘¦πŸ‡ΊπŸ‡³ΰΈ”ΰΈ΅ "];
+  [inputView deleteBackward];
+  [inputView deleteBackward];
+
+  // Thai vowel is removed.
+  XCTAssertEqualObjects(inputView.text, @"αžΉπŸ˜€ text πŸ₯°πŸ‘¨‍πŸ‘©‍πŸ‘§‍πŸ‘¦πŸ‡ΊπŸ‡³ΰΈ”");
+  [inputView deleteBackward];
+  XCTAssertEqualObjects(inputView.text, @"αžΉπŸ˜€ text πŸ₯°πŸ‘¨‍πŸ‘©‍πŸ‘§‍πŸ‘¦πŸ‡ΊπŸ‡³");
+  [inputView deleteBackward];
+  XCTAssertEqualObjects(inputView.text, @"αžΉπŸ˜€ text πŸ₯°πŸ‘¨‍πŸ‘©‍πŸ‘§‍πŸ‘¦");
+  [inputView deleteBackward];
+  XCTAssertEqualObjects(inputView.text, @"αžΉπŸ˜€ text πŸ₯°");
+  [inputView deleteBackward];
+
+  XCTAssertEqualObjects(inputView.text, @"αžΉπŸ˜€ text ");
+  [inputView deleteBackward];
+  [inputView deleteBackward];
+  [inputView deleteBackward];
+  [inputView deleteBackward];
+  [inputView deleteBackward];
+  [inputView deleteBackward];
+
+  XCTAssertEqualObjects(inputView.text, @"αžΉπŸ˜€");
+  [inputView deleteBackward];
+  XCTAssertEqualObjects(inputView.text, @"ឹ");
+  [inputView deleteBackward];
+  XCTAssertEqualObjects(inputView.text, @"");
+}
+
 - (void)testPastingNonTextDisallowed {
   NSDictionary* config = self.mutableTemplateCopy;
   [self setClientId:123 configuration:config];
diff --git a/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/xcshareddata/xcschemes/IosUnitTests.xcscheme b/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/xcshareddata/xcschemes/IosUnitTests.xcscheme
index 48aa290..b1341fc 100644
--- a/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/xcshareddata/xcschemes/IosUnitTests.xcscheme
+++ b/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/xcshareddata/xcschemes/IosUnitTests.xcscheme
@@ -78,6 +78,12 @@
             ReferencedContainer = "container:IosUnitTests.xcodeproj">
          </BuildableReference>
       </BuildableProductRunnable>
+      <CommandLineArguments>
+         <CommandLineArgument
+            argument = "--icu-data-file-path=Frameworks/Flutter.framework/icudtl.dat"
+            isEnabled = "YES">
+         </CommandLineArgument>
+      </CommandLineArguments>
    </LaunchAction>
    <ProfileAction
       buildConfiguration = "Release"