My app is crashing when I print a string with an emoji in it. This problem is only able to be duplicated with flutter web. The error message on crash is: Bad UTF-8 encoding found while decoding string: Here is a project which reproduces the issue.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
text:
'😄 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
style: TextStyle(color: Colors.black45, fontSize: 18)),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.text, this.style}) : super(key: key);
final String text;
final TextStyle style;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _textKey = GlobalKey();
final List<Rect> _textRects = [];
final List<Rect> _selectionRects = [];
String selectedText = '';
Rect _caretRect = Rect.zero;
MouseCursor _cursor = SystemMouseCursors.basic;
int _selectionBaseOffset;
TextSelection _textSelection = TextSelection.collapsed(offset: -1);
@override
initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_updateAllTextRects();
});
}
void _onMouseMove(event) {
if (event is PointerHoverEvent) {
if (_renderParagraph == null) {
return;
}
final allTextRects = _computeRectsForSelection(
TextSelection(baseOffset: 0, extentOffset: widget.text.length),
);
bool isOverText = false;
for (final rect in allTextRects) {
if (rect.contains(event.localPosition)) {
isOverText = true;
}
}
final newCursor =
isOverText ? SystemMouseCursors.text : SystemMouseCursors.basic;
if (newCursor != _cursor) {
setState(() {
_cursor = newCursor;
});
}
}
}
void _updateAllTextRects() {
setState(() {
_textRects
..clear()
..addAll(_computeRectsForSelection(
TextSelection(baseOffset: 0, extentOffset: widget.text.length)));
});
}
List<Rect> _computeRectsForSelection(TextSelection textSelection) {
if (_renderParagraph == null) {
return [];
}
final textBoxes = _renderParagraph.getBoxesForSelection(textSelection);
return textBoxes.map((box) => box.toRect()).toList();
}
RenderParagraph get _renderParagraph =>
_textKey.currentContext.findRenderObject() as RenderParagraph;
void _onPanStart(DragStartDetails details) {
if (_renderParagraph == null) {
return;
}
_selectionBaseOffset =
_renderParagraph.getPositionForOffset(details.localPosition).offset;
_textSelection = TextSelection.collapsed(offset: _selectionBaseOffset);
_updateSelectionDisplay();
}
void _updateSelectionDisplay() {
//Compute selection rectangles
final selectionRects = _computeRectsForSelection(_textSelection);
//Update caret display
final caretOffset =
_renderParagraph.getOffsetForCaret(_textSelection.extent, Rect.zero);
final caretHeight =
_renderParagraph.getFullHeightForCaret(_textSelection.extent);
setState(() {
_selectionRects
..clear()
..addAll(selectionRects);
_caretRect =
Rect.fromLTWH(caretOffset.dx - 1, caretOffset.dy, 2, caretHeight);
// widget.onSelectionChange?.call(_textSelection);
selectedText = _textSelection.textInside(widget.text);
print('selectedText: ' + selectedText.toString());
});
}
void _onPanUpdate(DragUpdateDetails details) {
final selectionExtentOffset =
_renderParagraph.getPositionForOffset(details.localPosition).offset;
_textSelection = TextSelection(
baseOffset: _selectionBaseOffset, extentOffset: selectionExtentOffset);
_updateSelectionDisplay();
}
void _onPanEnd(DragEndDetails details) {}
void _onPanCancel() {}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
color: Colors.white,
child: Center(
child: Listener(
onPointerHover: _onMouseMove,
child: MouseRegion(
cursor: _cursor,
child: GestureDetector(
onPanStart: _onPanStart,
onPanUpdate: _onPanUpdate,
onPanEnd: _onPanEnd,
onPanCancel: _onPanCancel,
child: Stack(
children: [
CustomPaint(
painter: _SelectionPainter(
color: Colors.yellow,
rects: _selectionRects,
fill: true),
),
CustomPaint(
painter: _SelectionPainter(
color: Colors.grey,
rects: _textRects,
fill: false),
),
Text(widget.text, key: _textKey, style: widget.style),
CustomPaint(
painter: _SelectionPainter(
color: Colors.blue,
rects: [_caretRect],
fill: true),
),
],
),
),
),
),
),
),
Text(selectedText, style: widget.style),
],
),
);
}
}
class _SelectionPainter extends CustomPainter {
_SelectionPainter({
@required Color color,
@required List<Rect> rects,
bool fill = true,
}) : _color = color,
_rects = rects,
_fill = fill,
_paint = Paint()..color = color;
final Color _color;
final List<Rect> _rects;
final bool _fill;
Paint _paint;
@override
void paint(Canvas canvas, Size size) {
//a rectangle
if (_fill == false) {
//make an outline of rectangle
_paint = Paint()
..color = _color
..style = PaintingStyle.stroke;
}
for (Rect _rect in _rects) {
canvas.drawRect(_rect, _paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
}
My app is crashing when I print a string with an emoji in it. This problem is only able to be duplicated with flutter web. The error message on crash is:
Bad UTF-8 encoding found while decoding string:Here is a project which reproduces the issue.Steps to Reproduce
flutter run -d chromefor web. It works fine in iOS.print('selectedText: ' + selectedText.toString());and then re-run the app, it will then select the emoji without any problems in the app.Bad UTF-8 encoding found while decoding string: