maxCharsPerSegment property

int get maxCharsPerSegment

The maximum number of characters that can fit in a single SMS segment given the current encoding.

This value changes depending on whether the message fits in one segment or requires multiple segments (concatenation). When concatenated, each segment includes a User Data Header (UDH) of 6 bytes (48 bits) that reduces the available space for message content.

Single-segment limits (no UDH):

Encoding Calculation Max characters
GSM-7 1120 bits ÷ 7 bits 160
UCS-2 1120 bits ÷ 16 bits 70

Multi-segment limits (with UDH per segment):

Encoding Calculation Max characters
GSM-7 (1120 − 48) bits ÷ 7 bits 153
UCS-2 (1120 − 48) bits ÷ 16 bits 67

Why does the value change?

  • Typing only GSM-7 characters (a-z, 0-9, basic punctuation) → the encoding is GSM-7 and you get 160 chars in one segment.
  • As soon as a non-GSM character (emoji, Chinese, Arabic, ç, etc.) is present → encoding switches to UCS-2 and the limit drops to 70.
  • Once the message exceeds one segment, the per-segment limit further reduces to 153 (GSM-7) or 67 (UCS-2) due to the UDH overhead.

Example:

final gsm = SegmentedMessage('Hello');
print(gsm.maxCharsPerSegment); // 160 (GSM-7, single segment)

final ucs2 = SegmentedMessage('Hello 😊');
print(ucs2.maxCharsPerSegment); // 70 (UCS-2, single segment)

final longGsm = SegmentedMessage('A' * 161);
print(longGsm.maxCharsPerSegment); // 153 (GSM-7, multi-segment)

Implementation

int get maxCharsPerSegment {
  const int maxBitsInSegment = 1120; // 140 bytes × 8 bits
  const int headerBits = 48; // 6 bytes × 8 bits (UDH for concatenated SMS)

  if (segments.length <= 1 &&
      !(segments.isNotEmpty && segments.first.hasUserDataHeader)) {
    // Single segment — no UDH overhead
    return maxBitsInSegment ~/ _bitsPerCharacter;
  }
  // Multi-segment — each segment includes a UDH
  return (maxBitsInSegment - headerBits) ~/ _bitsPerCharacter;
}