Convert Figma logo to code with AI

iziz logolibPhoneNumber-iOS

iOS port of Google's libphonenumber with Objective-C core, Swift facade, SwiftUI input, and CocoaPods/SPM support

2,386
483
2,386
0

Top Related Projects

Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers.

A Swift framework for parsing, formatting and validating international phone numbers. Inspired by Google's libphonenumber.

Generate Java types from JSON or JSON Schema and annotate those types for data-binding with Jackson, Gson, etc

PHP version of Google's phone number handling library

Quick Overview

libPhoneNumber-iOS is a port of Google's libphonenumber library for iOS. It provides functionality for parsing, formatting, and validating international phone numbers. This library is essential for developers working with phone numbers in iOS applications, offering a robust solution for handling various phone number formats across different countries.

Pros

  • Comprehensive phone number handling for multiple countries
  • Regular updates to keep pace with changing phone number formats
  • Well-documented and easy to integrate into iOS projects
  • Supports both Objective-C and Swift

Cons

  • Large library size may increase app bundle size
  • Occasional discrepancies with the original Google libphonenumber library
  • May require frequent updates to stay current with phone number changes
  • Performance can be slower for bulk operations

Code Examples

  1. Parsing a phone number:
let phoneUtil = NBPhoneNumberUtil()
do {
    let phoneNumber = try phoneUtil.parse("+1 650 253 0000", defaultRegion: "US")
    print(phoneNumber)
} catch {
    print("Error parsing number: \(error)")
}
  1. Formatting a phone number:
let phoneUtil = NBPhoneNumberUtil()
do {
    let phoneNumber = try phoneUtil.parse("+1 650 253 0000", defaultRegion: "US")
    let formattedNumber = try phoneUtil.format(phoneNumber, numberFormat: .INTERNATIONAL)
    print(formattedNumber) // Output: +1 650-253-0000
} catch {
    print("Error formatting number: \(error)")
}
  1. Validating a phone number:
let phoneUtil = NBPhoneNumberUtil()
do {
    let phoneNumber = try phoneUtil.parse("+1 650 253 0000", defaultRegion: "US")
    let isValid = phoneUtil.isValidNumber(phoneNumber)
    print("Is valid: \(isValid)") // Output: Is valid: true
} catch {
    print("Error validating number: \(error)")
}

Getting Started

  1. Add the library to your project using CocoaPods:
pod 'libPhoneNumber-iOS', '~> 0.9'
  1. Import the library in your Swift file:
import libPhoneNumber
  1. Create an instance of NBPhoneNumberUtil and start using the library:
let phoneUtil = NBPhoneNumberUtil()
// Use phoneUtil to parse, format, or validate phone numbers

Competitor Comparisons

Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers.

Pros of libphonenumber

  • More comprehensive and widely used, with support for multiple programming languages
  • Regularly updated with the latest phone number formats and metadata
  • Extensive documentation and community support

Cons of libphonenumber

  • Larger library size, which may impact app size and performance
  • More complex setup and integration process for iOS projects
  • Requires additional steps to use in Swift projects

Code Comparison

libPhoneNumber-iOS:

let phoneUtil = NBPhoneNumberUtil()
let phoneNumber = try phoneUtil.parse("+1 650 253 0000", defaultRegion: "US")
let isValid = phoneUtil.isValidNumber(phoneNumber)

libphonenumber:

PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
PhoneNumber phoneNumber = phoneUtil.parse("+1 650 253 0000", "US");
boolean isValid = phoneUtil.isValidNumber(phoneNumber);

Key Differences

  • libPhoneNumber-iOS is specifically designed for iOS development, while libphonenumber is a more general-purpose library
  • libPhoneNumber-iOS offers a more native Swift/Objective-C experience
  • libphonenumber provides broader language support and more frequent updates

Recommendation

Choose libPhoneNumber-iOS for iOS-specific projects that prioritize ease of integration and a native feel. Opt for libphonenumber if you need cross-platform support or require the most up-to-date phone number data and formats.

A Swift framework for parsing, formatting and validating international phone numbers. Inspired by Google's libphonenumber.

Pros of PhoneNumberKit

  • Written in Swift, providing better integration with modern iOS projects
  • Lightweight and has fewer dependencies
  • Offers a more Swifty API with better use of optionals and error handling

Cons of PhoneNumberKit

  • May have less comprehensive coverage of edge cases compared to libPhoneNumber-iOS
  • Potentially slower parsing performance for large datasets
  • Less frequent updates and maintenance

Code Comparison

libPhoneNumber-iOS:

NBPhoneNumberUtil *phoneUtil = [[NBPhoneNumberUtil alloc] init];
NSError *anError = nil;
NBPhoneNumber *myNumber = [phoneUtil parse:@"6012345678" 
                             defaultRegion:@"MY" error:&anError];

PhoneNumberKit:

let phoneNumberKit = PhoneNumberKit()
do {
    let phoneNumber = try phoneNumberKit.parse("6012345678", withRegion: "MY")
} catch {
    print("Parsing error: \(error)")
}

Both libraries provide similar functionality for parsing phone numbers, but PhoneNumberKit offers a more Swift-friendly syntax with better error handling through the use of do-try-catch blocks. libPhoneNumber-iOS, being Objective-C based, uses the traditional NSError pattern for error handling.

Generate Java types from JSON or JSON Schema and annotate those types for data-binding with Jackson, Gson, etc

Pros of jsonschema2pojo

  • Generates Java POJOs from JSON Schema, making it easier to work with JSON data in Java applications
  • Supports customization of generated code through annotations and configuration options
  • Can be integrated into build processes (Maven, Gradle) for automated code generation

Cons of jsonschema2pojo

  • Limited to Java language, while libPhoneNumber-iOS is specifically for iOS development
  • Requires additional setup and configuration compared to the more focused functionality of libPhoneNumber-iOS
  • May generate unnecessary code for simple JSON structures, potentially increasing project complexity

Code Comparison

jsonschema2pojo:

@JsonProperty("phoneNumber")
private String phoneNumber;

public String getPhoneNumber() {
    return phoneNumber;
}

libPhoneNumber-iOS:

let phoneUtil = NBPhoneNumberUtil()
let phoneNumber = try phoneUtil.parse("+1 650 253 0000", defaultRegion: "US")
let formattedNumber = try phoneUtil.format(phoneNumber, numberFormat: .NATIONAL)

While jsonschema2pojo generates Java classes for working with JSON data, libPhoneNumber-iOS provides specific functionality for parsing and formatting phone numbers in iOS applications. The code examples demonstrate the different focus areas of these libraries, with jsonschema2pojo handling JSON property mapping and libPhoneNumber-iOS dealing with phone number operations.

PHP version of Google's phone number handling library

Pros of libphonenumber-for-php

  • Written in PHP, making it easier to integrate with PHP-based projects
  • More actively maintained with frequent updates and contributions
  • Larger community support and more comprehensive documentation

Cons of libphonenumber-for-php

  • Not optimized for mobile platforms, potentially less efficient for iOS applications
  • Requires PHP runtime, which may not be ideal for iOS development environments
  • May have a larger footprint compared to native iOS libraries

Code Comparison

libphonenumber-for-php:

$phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance();
$phoneNumber = $phoneUtil->parse("+1 202-456-1414", "US");
$isValid = $phoneUtil->isValidNumber($phoneNumber);

libPhoneNumber-iOS:

let phoneUtil = NBPhoneNumberUtil()
let phoneNumber = try phoneUtil.parse("+1 202-456-1414", defaultRegion: "US")
let isValid = phoneUtil.isValidNumber(phoneNumber)

Both libraries offer similar functionality for parsing and validating phone numbers. The main difference lies in the language and ecosystem they're designed for. libphonenumber-for-php is better suited for PHP-based web applications, while libPhoneNumber-iOS is tailored for iOS app development. The choice between them depends on the specific project requirements and development environment.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

CocoaPods CocoaPods Swift Package Manager Carthage compatible

libPhoneNumber for iOS

Apple-platform port of Google's libphonenumber metadata and behavior, with a stable Objective-C core and Swift-first facades for modern Swift apps.

Use the Objective-C API when you need source-compatible legacy integration. Use the Swift facade modules when you want value-oriented parsing, formatting, validation, geocoding, short-number support, or a SwiftUI phone input.

Why This Library

  • Objective-C core remains the source of truth for parsing, formatting, validation, geocoding, and short-number behavior.
  • Swift facade modules provide smaller, task-focused imports for new Swift code.
  • SwiftUI phone input is available as an opt-in module instead of being bundled into the core parser.
  • Swift Package Manager and CocoaPods are both supported.
  • Metadata updates are tracked against Google libphonenumber with parity checks and review artifacts.

Recommended Setup

For most Swift apps, start with the core Swift facade:

.product(name: "libPhoneNumberSwiftCore", package: "libPhoneNumber")

Add optional modules only when needed:

.product(name: "libPhoneNumberSwiftGeocoding", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftShortNumber", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftCarrier", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftTimeZones", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftUI", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftUIEnrichment", package: "libPhoneNumber")

Use the umbrella product when you want one non-UI import for core, geocoding, and short-number facades:

.product(name: "libPhoneNumberIOSSwift", package: "libPhoneNumber")

For CocoaPods Swift apps:

pod 'libPhoneNumber-iOS-SwiftCore', '~> 1.7'

For the CocoaPods umbrella facade:

pod 'libPhoneNumber-iOS-Swift', '~> 1.7'

Then import the umbrella module as:

import libPhoneNumberIOSSwift

Products

ProductPackage managerUse when
libPhoneNumberSwiftCoreSPM, CocoaPodsYou need Swift parsing, formatting, validation, and as-you-type formatting.
libPhoneNumberSwiftGeocodingSPM, CocoaPodsYou need Swift offline geocoding on top of the core facade.
libPhoneNumberSwiftShortNumberSPM, CocoaPodsYou need Swift emergency-number and short-code support.
libPhoneNumberSwiftCarrierSPM, CocoaPodsYou need Swift carrier prefix lookup.
libPhoneNumberSwiftTimeZonesSPM, CocoaPodsYou need Swift timezone prefix lookup.
libPhoneNumberSwiftUISPM, CocoaPodsYou need a SwiftUI phone-number input component.
libPhoneNumberSwiftUIEnrichmentSPM, CocoaPodsYou want carrier/timezone metadata connected to SwiftUI field state.
libPhoneNumberIOSSwiftSPM, CocoaPods umbrella moduleYou want one non-UI Swift import for core, geocoding, and short-number facades.
libPhoneNumberSPM, CocoaPods, Carthage, manualYou need the stable Objective-C core API.
libPhoneNumberGeocodingSPM, CocoaPodsYou need Objective-C offline geocoding APIs.
libPhoneNumberShortNumberSPM, CocoaPodsYou need Objective-C emergency-number and short-code APIs.
libPhoneNumberCarrierSPM, CocoaPodsYou need Objective-C carrier prefix lookup APIs.
libPhoneNumberTimeZonesSPM, CocoaPodsYou need Objective-C timezone prefix lookup APIs.

The SwiftUI module is intentionally separate from the umbrella module because it is UI-specific and requires SwiftUI runtime availability.

Choose the smallest product that matches the app. Geocoding, carrier, and timezone modules are opt-in because they ship metadata bundles. Carrier names are original-assignment hints and may be misleading in mobile-number-portable regions; use the safe-display API for user-facing carrier labels. Timezone lookup returns possible CLDR timezone IDs from prefix metadata, not the user's current location.

Installation

Swift Package Manager

Add this repository as a package dependency:

https://github.com/iziz/libPhoneNumber-iOS

Select only the products your app needs:

.product(name: "libPhoneNumberSwiftCore", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftGeocoding", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftShortNumber", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftCarrier", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftTimeZones", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftUI", package: "libPhoneNumber")
.product(name: "libPhoneNumberSwiftUIEnrichment", package: "libPhoneNumber")
.product(name: "libPhoneNumberIOSSwift", package: "libPhoneNumber")

Objective-C-compatible products are also available:

.product(name: "libPhoneNumber", package: "libPhoneNumber")
.product(name: "libPhoneNumberGeocoding", package: "libPhoneNumber")
.product(name: "libPhoneNumberShortNumber", package: "libPhoneNumber")
.product(name: "libPhoneNumberCarrier", package: "libPhoneNumber")
.product(name: "libPhoneNumberTimeZones", package: "libPhoneNumber")

CocoaPods

Core Objective-C API:

pod 'libPhoneNumber-iOS', '~> 1.7'

Swift facade modules:

pod 'libPhoneNumber-iOS-SwiftCore', '~> 1.7'
pod 'libPhoneNumber-iOS-SwiftGeocoding', '~> 1.7'
pod 'libPhoneNumber-iOS-SwiftShortNumber', '~> 1.7'
pod 'libPhoneNumber-iOS-SwiftCarrier', '~> 1.7'
pod 'libPhoneNumber-iOS-SwiftTimeZones', '~> 1.7'
pod 'libPhoneNumber-iOS-SwiftUI', '~> 1.7'
pod 'libPhoneNumber-iOS-SwiftUIEnrichment', '~> 1.7'

Swift umbrella facade:

pod 'libPhoneNumber-iOS-Swift', '~> 1.7'

Objective-C optional modules:

pod 'libPhoneNumberGeocoding', '~> 1.7'
pod 'libPhoneNumberShortNumber', '~> 1.7'
pod 'libPhoneNumberCarrier', '~> 1.7'
pod 'libPhoneNumberTimeZones', '~> 1.7'

Carthage

Add this to your Cartfile:

github "iziz/libPhoneNumber-iOS"

Manual Integration

Add the source files from the modules you need and link Contacts.framework for the core library.

Swift Quick Start

Prefer libPhoneNumberSwiftCore for new Swift code that only needs parsing, formatting, validation, and as-you-type formatting:

import libPhoneNumberSwiftCore

let phoneUtil = PhoneNumberUtility.shared
let phoneNumber = try phoneUtil.parse("01065431234", defaultRegion: "KR")

let e164 = try phoneUtil.format(phoneNumber, as: .e164)
let isValid = phoneUtil.isValidNumber(phoneNumber)
let numberType = phoneUtil.type(of: phoneNumber)

The Swift facade delegates to the Objective-C implementation. Phone-number parsing and validation logic should stay in the Objective-C core so upstream behavior remains centralized.

For storage, concurrency boundaries, or API responses, use the immutable value wrapper:

let value = try phoneUtil.value(from: "01065431234", defaultRegion: "KR").get()

value.e164
value.regionCode
value.nationalSignificantNumber
value.type

As-You-Type Formatting

import libPhoneNumberSwiftCore

let formatter = AsYouTypeFormatter(regionCode: "US")

formatter.inputDigit("6") // "6"
formatter.inputDigit("5") // "65"
formatter.inputDigit("0") // "650"
formatter.inputDigit("2") // "650-2"

Short Numbers

import libPhoneNumberSwiftCore
import libPhoneNumberSwiftShortNumber

let phoneUtil = PhoneNumberUtility.shared
let shortUtil = ShortNumberUtility.shared
let number = try phoneUtil.parse("911", defaultRegion: "US")

shortUtil.isValidShortNumber(number, forRegion: "US")
shortUtil.connectsToEmergencyNumber("911", forRegion: "US")
shortUtil.expectedCost(of: number, forRegion: "US")

Geocoding

import libPhoneNumberSwiftCore
import libPhoneNumberSwiftGeocoding

let phoneUtil = PhoneNumberUtility.shared
let geocoder = PhoneNumberGeocoder.shared
let number = try phoneUtil.parse("16502530000", defaultRegion: "US")

let description = geocoder.description(for: number, languageCode: "en")

Carrier

import libPhoneNumberSwiftCore
import libPhoneNumberSwiftCarrier

let phoneUtil = PhoneNumberUtility.shared
let mapper = PhoneNumberCarrierMapper.shared
let number = try phoneUtil.parse("+244917654321", defaultRegion: "AO")

let carrier = mapper.safeDisplayName(for: number, localeCode: "en")

Timezones

import libPhoneNumberSwiftCore
import libPhoneNumberSwiftTimeZones

let phoneUtil = PhoneNumberUtility.shared
let mapper = PhoneNumberTimeZonesMapper.shared
let number = try phoneUtil.parse("16502530000", defaultRegion: "US")

let timeZones = mapper.timeZones(for: number)

SwiftUI Phone Input

import SwiftUI
import libPhoneNumberSwiftUI

struct PhoneForm: View {
  @State private var phoneNumber = ""
  @State private var e164: String?

  var body: some View {
    PhoneNumberTextField(
      "Phone number",
      text: $phoneNumber,
      defaultRegion: "US",
      onStateChange: { state in
        e164 = state.e164
      },
      regionPicker: { region in
        Text(region)
      }
    )
  }
}

SwiftUI Carrier And Timezone Enrichment

import SwiftUI
import libPhoneNumberSwiftUI
import libPhoneNumberSwiftUIEnrichment

struct EnrichedPhoneForm: View {
  @State private var phoneNumber = ""
  @State private var carrierName: String?
  @State private var timeZones: [String] = []

  private let formatter = PhoneNumberFieldFormatter(
    enricher: CarrierTimeZonesPhoneNumberEnricher(localeCode: "en")
  )

  var body: some View {
    PhoneNumberTextField(
      "Phone number",
      text: $phoneNumber,
      defaultRegion: "AO",
      formatter: formatter,
      onStateChange: { state in
        carrierName = state.enrichment?.carrierName
        timeZones = state.enrichment?.timeZones ?? []
      }
    )
  }
}

Objective-C Usage

Use NBPhoneNumberUtil when integrating from Objective-C or when you need direct access to the core API:

NBPhoneNumberUtil *phoneUtil = [NBPhoneNumberUtil sharedInstance];
NSError *error = nil;

NBPhoneNumber *phoneNumber = [phoneUtil parse:@"6766077303"
                                defaultRegion:@"AT"
                                        error:&error];

if (phoneNumber != nil && error == nil) {
  NSLog(@"isValidPhoneNumber ? %@", [phoneUtil isValidNumber:phoneNumber] ? @"YES" : @"NO");

  NSLog(@"E164          : %@", [phoneUtil format:phoneNumber
                                    numberFormat:NBEPhoneNumberFormatE164
                                           error:&error]);
  NSLog(@"INTERNATIONAL : %@", [phoneUtil format:phoneNumber
                                    numberFormat:NBEPhoneNumberFormatINTERNATIONAL
                                           error:&error]);
  NSLog(@"NATIONAL      : %@", [phoneUtil format:phoneNumber
                                    numberFormat:NBEPhoneNumberFormatNATIONAL
                                           error:&error]);
  NSLog(@"RFC3966       : %@", [phoneUtil format:phoneNumber
                                    numberFormat:NBEPhoneNumberFormatRFC3966
                                           error:&error]);
} else {
  NSLog(@"Error: %@", error.localizedDescription);
}

Objective-C As-You-Type Formatting

NBAsYouTypeFormatter *formatter = [[NBAsYouTypeFormatter alloc] initWithRegionCode:@"US"];

NSLog(@"%@", [formatter inputDigit:@"6"]); // "6"
NSLog(@"%@", [formatter inputDigit:@"5"]); // "65"
NSLog(@"%@", [formatter inputDigit:@"0"]); // "650"
NSLog(@"%@", [formatter inputDigit:@"2"]); // "650-2"

Swift Bridging For Legacy Integrations

Existing Swift projects can continue to import Objective-C headers directly.

For manual integration:

#import "NBPhoneNumberUtil.h"
#import "NBPhoneNumber.h"

For CocoaPods:

#import "libPhoneNumber_iOS/NBPhoneNumberUtil.h"
#import "libPhoneNumber_iOS/NBPhoneNumber.h"

New Swift code should prefer libPhoneNumberSwiftCore unless it specifically needs geocoding, short-number support, or Objective-C API details.

Metadata Freshness

Phone-number behavior is driven by Google's libphonenumber metadata. Metadata or upstream behavior changes should be reviewed in a normal PR with:

  • The Google libphonenumber version or commit used.
  • Main metadata changes.
  • Geocoding metadata changes, if applicable.
  • Upstream test parity results.
  • Upstream API parity results.
  • Local validation results.

Generate a current-vs-upstream freshness report:

swift scripts/checkMetadataFreshness.swift --output .build/metadata-freshness

The script writes review artifacts only. It does not modify checked-in metadata.

For user-reported numbering-plan gaps that are not yet in upstream metadata, follow the metadata patch policy. Local metadata overrides must be evidence-backed, tested, and removed once upstream includes the change.

Updating Metadata

Use the all-in-one updater for normal metadata releases:

swift scripts/updateMetadata.swift <libphonenumber-version> --dry-run
swift scripts/updateMetadata.swift <libphonenumber-version>

Use --only main,geocoding or --skip carrier,timezones when the release intentionally covers only specific metadata families. See the release runbook for the full release flow.

Direct Metadata Scripts

Use the individual generators only when debugging or intentionally updating one metadata family outside the normal release flow:

swift scripts/metadataGenerator.swift <libphonenumber-version> --pretty
swift scripts/updateGeocodingMetadata.swift <libphonenumber-version> --replace-bundle
swift scripts/updateCarrierMetadata.swift <libphonenumber-version> --replace-bundle
swift scripts/updateTimeZonesMetadata.swift <libphonenumber-version> --replace-bundle

Use --output to inspect generated review artifacts before replacing checked-in bundles. Use --source with the individual scripts when you already have a local Google libphonenumber checkout or extracted resource directory.

Validation

Before merging behavior, metadata, packaging, or API changes, run the relevant checks from docs/TESTING.md.

Common local checks:

swift scripts/checkVersionConsistency.swift
swift test
LC_ALL=ko_KR.UTF-8 LANG=ko_KR.UTF-8 swift test
swift build -c release
git diff --check

For Swift facade changes:

swift scripts/publishPodspecs.swift --lint

For Xcode schemes:

swift scripts/testXcodeSchemes.swift

Release Checklist

  1. Decide the next version:
    • Patch for bug fixes or metadata-only updates.
    • Minor for additive functionality or public API additions.
    • Major for breaking changes.
  2. Update project versions:
    swift scripts/updateProjectVersions.swift <new-version>
    
  3. Run the validation matrix.
  4. Lint podspecs:
    swift scripts/publishPodspecs.swift --lint
    
  5. Open a pull request with upstream version, parity results, and test results.
  6. Create a GitHub release after merge.
  7. Push updated podspecs in dependency order:
    swift scripts/publishPodspecs.swift
    swift scripts/publishPodspecs.swift --publish
    

Maintenance Guides

Links