Leverages libphonenumber to allow for asynchronous and synchronous formatting of phone numbers in Flutter apps

Overview

flutter_libphonenumber

A wrapper around libphonenumber with added functionality merged from the following libs:

Uses the following native libraries:

Platform Library Version
Android libphonenumber 8.12.24
iOS PhoneNumberKit 3.3

The main advantage to this lib is it lets you optionally format a phone number synchronously without making calls into libphonenumber with platform calls.

AsYouType real-time formatting

Format and parse

Getting Started

First you need to call the init function. This will load all of the available regions available on the device from libphonenumber to build a formatting mask for each country using its example number from libphonenumber.

If you don't run the init function then formatNumberSync will simply return the same thing passed into it without formatting anything as there won't be any masks to utilize.

We use the same approach from flutter_multi_formatter for masking but instead of statically defining all of our country masks, we pull them on the fly from libphonenubmer so that the masks will be automatically maintained over time.

You can either do this during your app init before calling RunApp, or with a FutureBuilder as the example app demonstrates.

await FlutterLibphonenumber().init();

Formatting a number synchronously

Normally calls to libphonenumber's format function are asynchronous, and you might not want your UI rebuilding every time you need to format a phone number.

To get around this, we load a mask of every supported phone region's example number from libphonenumber during the init() call. We can then use this mask to format an e164 phone number synchronously like this:

final rawNumber = '+14145556666';
final formattedNumber = FlutterLibphonenumber().formatNumberSync(rawNumber); // +1 414-555-6666

CountryManager

When you call init, this lib will store a list of the countries and phone metadata with the following class:

class CountryWithPhoneCode {
  final String phoneCode                            // '44',
  final String countryCode                          // 'GB',
  final String exampleNumberMobileNational          // '07400 123456',
  final String exampleNumberFixedLineNational       // '0121 234 5678',
  final String phoneMaskMobileNational              // '00000 000000',
  final String phoneMaskFixedLineNational           // '0000 000 0000',
  final String exampleNumberMobileInternational     // '+44 7400 123456',
  final String exampleNumberFixedLineInternational  // '+44 121 234 5678',
  final String phoneMaskMobileInternational         // '+00 0000 000000',
  final String phoneMaskFixedLineInternational      // '+00 000 000 0000',
  final String countryName                          // 'United Kingdom';
}

To access this list of countries you can get at it like this:

final countries = CountryManager().countries; // List
   

API Reference

Here is a reference of all of the available functions.

Future init({Map overrides})

Must be called before we can format anything. This loads all available countries on the device and calls getAllSupportedRegions() to then cross-reference and combine everything and save a List of every available country with its phone code / mask.

Optionally provide a map of overrides where the key is the country code (ex: GB or US) and the value is a CountryWithPhoneCode object that should replace the data pulled from libphonenumber. This is useful if you want to customize the mask data for a given country.

Future > getAllSupportedRegions()

Returns all of the available regions on the device in a map with each key as the region code, and the value as a CountryWithPhoneCode object containing all of the mobile and landline phone masks / example numbers for national / international format, phone code, region code, and country name.

Example response:

{
  "UK": [CountryWithPhoneCode()],
  "US": [CountryWithPhoneCode()]
}

Future > format(String phone, String region)

Formats a number using libphonenumber. Under the hood this is using the AsYouType formatter. Depending on your result, you might want to use formatNumberSync() to utilize the phone number masks.

Will return the parsed / formatted number like this:

{
    formatted: "1 (414) 444-4444",
}

Future > parse(String phone, {String region})

Parses a number and if it is full and complete, returns some metadata associated with the number. The number must be a valid and compelte e164 formatted number to be considered valid.

Will throw an error if the number isn't valid.

Example response:

{
    country_code: 49,
    e164: '+4930123123123',
    national: '030 123 123 123',
    type: 'mobile',
    international: '+49 30 123 123 123',
    national_number: '030123123123',
}

String formatNumberSync(String number, {CountryWithPhoneCode? country, PhoneNumberType phoneNumberType = PhoneNumberType.mobile, phoneNumberFormat = PhoneNumberFormat.international, bool removeCountryCodeFromResult = false, bool inputContainsCountryCode = true})

Format a number synchronously using masks to format it. Must have ran the init() function to pre-populate the mask data or else the original phone value will be returned.

Optionally specify the phone number type to format it as (mobile vs fixedLine). This is useful when a country has more than one phone number format and you want to format it to either fit the fixed line or mobile pattern.

Use removeCountryCodeFromResult to remove the country code from the formatted result. Set inputContainsCountryCode accordingly based on if the inputted number to format contains the country code or not.

Example response:

"1 (414) 444-4444"

Future getFormattedParseResult(String phoneNumber,CountryWithPhoneCode country, {PhoneNumberType phoneNumberType = PhoneNumberType.mobile, PhoneNumberFormat phoneNumberFormat = PhoneNumberFormat.international,})

Asynchronously formats a phone number with libphonenumber. Will return the formatted number and if it's a valid/complete number, will return the e164 value as well in the e164 field. Uses libphonenumber's parse function to verify if it's a valid number or not. This is useful if you want to format a number and also check if it's valid, in one step.

Optionally pass a PhoneNumberType to format the number using either the mobile (default) or fixed line mask.

e164 will be null if the number is not valid.

class FormatPhoneResult {
  String formattedNumber; // 1 (414) 444-4444
  String e164; // +14144444444
}

TextInputFormatter LibPhonenumberTextFormatter(...)

  • required String country You must provide the country used to format the text accurately.

The text formatter also takes 5 optional arguments:

  • PhoneNumberType? phoneNumberType specify whether to format the phone number in the mobile format using the mask for mobile numbers, or the fixed line format. Can either be PhoneNumberType.mobile or PhoneNumberType.fixedLine. Defaults to PhoneNumberType.mobile.

  • PhoneNumberFormat? phoneNumberFormat specify to format using the national or international format. Can either be PhoneNumberFormat.international or PhoneNumberFormat.national. Defaults to PhoneNumberFormat.international.

  • FutureOr Function(String val) onFormatFinished Optionally get a notification at this callback of the final formatted value once all formatting is completed. This is useful if you want to do something else that is triggered after formatting is done.

  • bool? inputContainsCountryCode When true, mask will be applied assuming the input contains a country code in it.

  • int? additionalDigits You can tell the formatter to allow additional digits on the end of the mask. This is useful for some countries which have a similar mask but varying length of numbers. It's safe to set this to a value like 3 or 5 and you won't have to think about it again.

To use it, simply add LibPhonenumberTextFormatter() to your TextField's inputFormatters list:

TextField(inputFormatters: [LibPhonenumberTextFormatter(
  country: 'GB',
)])
Comments
  • Error while running in iOS with the latest flutter SDK 1.22.1

    Error while running in iOS with the latest flutter SDK 1.22.1

    Getting the below error in iOS

    error: compiling for iOS 8.0, but module 'PhoneNumberKit' has a minimum deployment target of iOS 9.0: .....PhoneNumberKit/PhoneNumberKit.framework/Modules/PhoneNumberKit.swiftmodule/arm64-apple-ios.swiftmodule import PhoneNumberKit ^

    opened by bharathiselvan 8
  • Brazil(+55)'s phoneNumber format is wrong

    Brazil(+55)'s phoneNumber format is wrong

    I've just found your lib and I would like to use it, but what I need more is that the phone format works for Brazil's phone number.

    In Brasil we have 2 different types of format numbers +55 (xx) xxxx-xxxx [for residential numbers] and +55 (xx) xxxxx-xxxx [for cellphones].

    Your solution only works for residential numbers, but what we really need is that it works for cellphone numbers. It would be really helpful if you could fix that!

    "As established by ANATEL, the Brazilian federal telecommunications regulatory agency, the format for a local phone number is nnnn-nnnn (eight digits) for landlines, and nnnnn-nnnn (nine digits) for mobile lines." https://en.wikipedia.org/wiki/Telephone_numbers_in_Brazil

    Thanks a lot!

    opened by andrealvaradodearaujo 8
  • Converting Local Phone Number Based on User's Locale

    Converting Local Phone Number Based on User's Locale

    How do we achieve this. Let's say the phone number is 016123456 and the user's device is located in Singapore (+65). How do we convert it automatically using the library to +6516123456.

    Any thoughts? Thank you

    opened by Jayvd 6
  • Mobile number in CIV got changed from 8 to 10 digits

    Mobile number in CIV got changed from 8 to 10 digits

    All ORANGE cell phone numbers after the country code (+225) now start with 07 All MTN cell phone numbers after the country code (+225) now start with 05 All MOOV cell phone numbers after the country code (+225) now start with 01

    Can we have this fixed please?

    opened by AhmadKsb 5
  • Austrian Phone number missing 1 digit

    Austrian Phone number missing 1 digit

    when entering an austrian mobile number there is one digit missing.

    for example the number is 664 1234567 but the inputformatter stops at 664 123456

    I think it is the same problem as in #4 with a different country

    opened by emmaxCreative 5
  • Phone number is truncated

    Phone number is truncated

    opened by Adam-Langley 5
  • Example is not working as expected

    Example is not working as expected

    Hello,

    I'm currently searching a library to handle the phone number changes in Ivory coast (details here: link ).

    I'm trying to test this library by running the example and see if everything is working as expected and unfortunately it's not. The test I'm running is the following :

    import "package:test/test.dart";
    import 'package:flutter_libphonenumber/flutter_libphonenumber.dart';
    
    void main() {
      group('flutter_libphonenumber library testing', () {
        setUpAll(() async {
          await FlutterLibphonenumber().init();
        });
    
        test(
          'should parse phonenumber',
          () {
            final rawNumber = '+14145556666';
            final formattedNumber =
                FlutterLibphonenumber().formatNumberSync(rawNumber);
    
            expect(formattedNumber, "+1 414-555-6666");
          },
        );
      });
    }
    

    And the output is the following :

    Expected: '+1 414-555-6666'
      Actual: '14145556666'
       Which: is different.
              Expected: +1 414-555 ...
                Actual: 1414555666 ...
                        ^
               Differ at offset 0
    

    Is this a bug or am I doing something wrong ? Thank you in advance for the help !

    opened by monisnap-julien 4
  • Parse national number

    Parse national number

    Hi, I have tried using your lib to parse and format numbers, especially french national number. I want to parse this number '06 06 06 06 06' with the region 'FR', and I'm expecting to get a valid parsing, corresponding to the international number '+33 6 06 06 06 06'. But I get an exception : PlatformException(InvalidNumber, Number +06 06 06 06 06 is invalid, null, null). I have checked on this LibPhoneNumber demo : https://libphonenumber.appspot.com/ and I have tested it in an Android project with the native lib and it works fine. I guess the problem is that you add a leading '+' with the method _ensureLeadingPlus(phone) before using the native library methods. In the case of french numbers, '0606060606' is a valid national number, but '+0606060606' isn't.

    opened by mfarizon 4
  • Update the parse method and upgrade the dependencies.

    Update the parse method and upgrade the dependencies.

    • Adds a new field (region_code) to the result of the parse method.
    • Upgrades the dependencies:
      • libphonenumber to 8.12.52
      • PhoneNumberKit to 3.3.4
    • Fixes some lint issues.
    opened by laurent-sf 3
  • Why deviceLocaleCountryCode is gone?

    Why deviceLocaleCountryCode is gone?

    I was using CountryManager().deviceLocaleCountryCode, but since I moved to 1.x to enable null safety, this var does not exist anymore. Why? It's was useful for selecting the default country of the user.

    opened by julienlebren 3
  • Returns 0 country

    Returns 0 country

    final sortedCountries = CountryManager().countries
                                ..sort((a, b) => (a.countryName ?? '')
                                    .compareTo(b.countryName ?? ''));
    

    As mentioned in the demo above statement return 0.

    opened by him123 2
  • Different parse results with the same number

    Different parse results with the same number

    flutter_libphonenumber: ^1.2.4

    When parsing a number with no regionCode, for example 01114377479 (An Egyptian number), sometimes it returns +201114377479, other times it fails to parse. Why would there be this inconsistency, how can i help?

    opened by yassinsameh 1
  • Incorrect for Malaysian Phone Numbers with prefix 6011

    Incorrect for Malaysian Phone Numbers with prefix 6011

    Some valid Malaysian mobile phone numbers start with 6011 and contains 12 digits such as 6011-1234-5678. This library does not recognise such numbers.

    opened by jinfeei 1
  • Wrong mask being set after upgrade to version 1.2.1

    Wrong mask being set after upgrade to version 1.2.1

    We are using this library in two different projects, applying masks for brazilian phone numbers. The first one is using version 1.1.0 and the second started using this lib with version 1.2.1. We notice that the mask is not being applied correctly in version 1.2.1.

    With 1.1.0, the correct mask is: +55 (XX) XXXXX-XXXX With 1.2.1, the wrong mask is +55 XXXXX-XXXX

    We had to downgrade to version 1.1.0 in both projects.

    Tested only in iOS, with latest Flutter version (stable).

    opened by emersonsiega 2
  • removeCountryCodeFromMask results in incorrect phone mask for national numbers

    removeCountryCodeFromMask results in incorrect phone mask for national numbers

    Calling this text formatter:

    LibPhonenumberTextFormatter( country: usCountry, PhoneNumberFormat.national)

    Will result in the following mask "0) 000-0000" It should be "(000) 000-0000"

    There are a couple problems:

    1. input_formatter.dart line 28: removeCountryCodeFromMask gets set to true even though the phone number is a national number and the inputContainsCountryCode is false.

    2. Once removeCountryCodeFromMask is true country_data.dart line 188 will remove three characters from the beginning of the national mask therefore chopping off the area code portion of the national phone number mask.

    opened by woelmer 0
  • Delete number in the TextField the cursor is moved to the end of the text.

    Delete number in the TextField the cursor is moved to the end of the text.

    Hello, This is My TextField

    TextField(
                              keyboardType: TextInputType.phone,
                              controller: textEdtControllerMobileNumber,
                              autofocus: true,
                                                     inputFormatters: [
                                LibPhonenumberTextFormatter(
                                  phoneNumberType: globalPhoneType,
                                  phoneNumberFormat: globalPhoneFormat,
                                  country: countryWithPhonenum,
                                  hideCountryCode: true,
                                  additionalDigits: 3,
                                ),
                              ],                         
                            ))
    

    The problem is when I input the number in the TextField, let's say 123456789 then I want to remove the number 3 when I take the cursor after number 3 and remove it the cursor will be automatically goes to the end of the number after 9 instead of it should keep it cursor position after 2.

    I hope I explained the issue well.

    enhancement 
    opened by him123 2
Owner
Bottlepay
Limitless payments for a borderless world
Bottlepay
null 1 Jan 29, 2022
Eder Zambrano 0 Feb 13, 2022
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
Package provides light widgets [for Linkify, Clean] and extensions for strings that contain bad words/URLs/links/emails/phone numbers

Package provides light widgets [for Linkify, Clean] and extensions for strings that contain bad words/URLs/links/emails/phone numbers

BetterX.io 4 Oct 2, 2022
⚡FQuery is a powerful async state management solution for flutter. It caches, updates and fully manages asynchronous data in your flutter apps.

⚡ FQuery is a powerful async state management solution for flutter. It caches, updates and fully manages asynchronous data in your flutter apps. It ca

Piyush 21 Dec 22, 2022
Starter project for Flutter plugins willing to access native and synchronous rust code using FFI

Flutter Rust FFI Template This project is a Flutter Plugin template. It provides out-of-the box support for cross-compiling native Rust code for all a

Jør∂¡ 561 Dec 7, 2022
A fast, extra light and synchronous key-value storage to Get framework

get_storage A fast, extra light and synchronous key-value in memory, which backs up data to disk at each operation. It is written entirely in Dart and

Jonny Borges 257 Dec 21, 2022
Presentation-Remote-PC - Manage your presentation from your smart phone - Phone Client

Presentation-Remote-PC Manage your presentation from your smart phone - Phone Cl

Hasan Ragab Eltantawy 1 Jan 25, 2022
A package that exports functions for converting, formatting, and nicening of dates/times in Dart.

Instant A library for manipulating and formatting DateTimes in Dart. Dates and times have never been easier. | DateTime timezone manipulation | Easy f

Aditya Kishore 10 Jan 22, 2022
WYSIWYG editor for Flutter with a rich set of supported formatting options. (WIP)

✨ rich_editor WYSIWYG editor for Flutter with a rich set of supported formatting options. Based on https://github.com/dankito/RichTextEditor, but for

Festus Olusegun 116 Dec 27, 2022
"FlutterMoneyFormatter" is a Flutter extension to formatting various types of currencies according to the characteristics you like, without having to be tied to any localization.

FlutterMoneyFormatter FlutterMoneyFormatter is a Flutter extension to formatting various types of currencies according to the characteristics you like

Fadhly Permata 81 Jan 1, 2023
A sophisticated tool for managing queues of asynchronous tasks, with a stream interface, strong typing and lots of helpful options.

Secretary A sophisticated task manager. Secretary is a tool for keeping your futures in check. It's useful for managing queues of asynchronous tasks,

Alex Baker 5 Dec 21, 2022
An asynchronous Kaboom wrapper, written in Dart.

Kaboom Dart An asynchronous Kaboom wrapper, written in Dart. Usage To get started, initialize a Kaboom instane: // Initializes a new Kaboom instance.

kaboom 0 Apr 7, 2022
Now UI Flutter is a fully coded app template built for Flutter which will allow you to create powerful and beautiful e-commerce mobile applications

Now UI Flutter is a fully coded app template built for Flutter which will allow you to create powerful and beautiful e-commerce mobile applications. We have redesigned all the usual components to make it look like our Now UI Design, minimalistic and easy to use.

null 12 Oct 9, 2022
A Flutter plugin than allow expand and collapse text dynamically

readmore A Flutter plugin than allow expand and collapse text. usage: add to your pubspec readmore: ^1.0.2 and import: import 'package:readmore/readm

Jonny Borges 173 Dec 28, 2022
Flutter application for latest news by top newspapers . And allow for share articles with friends. Now available in night mode. Also landscape mode is available

Breaking News Latest news for almost 55 country. Feature of saving article and search ariticles. Used API https://newsapi.org/ Note: if data is not ge

null 7 Oct 24, 2022
Flutter package for Android and iOS allow you to show a wide range of hyperlinks either in the input field or in an article view

Tagtly package help you to detect a lot of hyperlink text such as.. email, url, social media tags, hashtag and more either when user type in text field or when appear a text read only.

Mohamed Nasr 4 Jul 25, 2022
A Flutter package that extends IndexedStack to allow for lazy loading.

lazy_load_indexed_stack A package that extends IndexedStack to allow for lazy loading. Motivation If you use the IndexedStack with bottom navigation,

Ryotaro Oka 18 Dec 16, 2022