libPhoneNumber-iOS
iOS port of Google's libphonenumber with Objective-C core, Swift facade, SwiftUI input, and CocoaPods/SPM support
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
- 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)")
}
- 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)")
}
- 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
- Add the library to your project using CocoaPods:
pod 'libPhoneNumber-iOS', '~> 0.9'
- Import the library in your Swift file:
import libPhoneNumber
- Create an instance of
NBPhoneNumberUtiland 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
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
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
| Product | Package manager | Use when |
|---|---|---|
libPhoneNumberSwiftCore | SPM, CocoaPods | You need Swift parsing, formatting, validation, and as-you-type formatting. |
libPhoneNumberSwiftGeocoding | SPM, CocoaPods | You need Swift offline geocoding on top of the core facade. |
libPhoneNumberSwiftShortNumber | SPM, CocoaPods | You need Swift emergency-number and short-code support. |
libPhoneNumberSwiftCarrier | SPM, CocoaPods | You need Swift carrier prefix lookup. |
libPhoneNumberSwiftTimeZones | SPM, CocoaPods | You need Swift timezone prefix lookup. |
libPhoneNumberSwiftUI | SPM, CocoaPods | You need a SwiftUI phone-number input component. |
libPhoneNumberSwiftUIEnrichment | SPM, CocoaPods | You want carrier/timezone metadata connected to SwiftUI field state. |
libPhoneNumberIOSSwift | SPM, CocoaPods umbrella module | You want one non-UI Swift import for core, geocoding, and short-number facades. |
libPhoneNumber | SPM, CocoaPods, Carthage, manual | You need the stable Objective-C core API. |
libPhoneNumberGeocoding | SPM, CocoaPods | You need Objective-C offline geocoding APIs. |
libPhoneNumberShortNumber | SPM, CocoaPods | You need Objective-C emergency-number and short-code APIs. |
libPhoneNumberCarrier | SPM, CocoaPods | You need Objective-C carrier prefix lookup APIs. |
libPhoneNumberTimeZones | SPM, CocoaPods | You 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
- Decide the next version:
- Patch for bug fixes or metadata-only updates.
- Minor for additive functionality or public API additions.
- Major for breaking changes.
- Update project versions:
swift scripts/updateProjectVersions.swift <new-version> - Run the validation matrix.
- Lint podspecs:
swift scripts/publishPodspecs.swift --lint - Open a pull request with upstream version, parity results, and test results.
- Create a GitHub release after merge.
- Push updated podspecs in dependency order:
swift scripts/publishPodspecs.swift swift scripts/publishPodspecs.swift --publish
Maintenance Guides
Links
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
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot