Objective-C implementation of Google's libphonenumber metadata and behavior for Apple platforms, with a Swift-first facade for new Swift integrations.
The project keeps the Objective-C core stable for existing apps while exposing a smaller Swift API for common parsing, formatting, validation, geocoding, and short-number workflows.
| Product | Use when |
|---|---|
libPhoneNumberSwift |
You are writing new Swift code and want a native-feeling facade. |
libPhoneNumber |
You need the stable Objective-C core API. |
libPhoneNumberGeocoding |
You need offline region descriptions for phone numbers. |
libPhoneNumberShortNumber |
You need emergency and short-code support. |
Add this repository as a package dependency and select the products you need.
For most Swift apps, choose:
.product(name: "libPhoneNumberSwift", package: "libPhoneNumber")Use the Objective-C-compatible products directly if you need lower-level access:
.product(name: "libPhoneNumber", package: "libPhoneNumber")
.product(name: "libPhoneNumberGeocoding", package: "libPhoneNumber")
.product(name: "libPhoneNumberShortNumber", package: "libPhoneNumber")For Objective-C-compatible core APIs:
pod 'libPhoneNumber-iOS', '~> 1.4'For the Swift-first facade:
pod 'libPhoneNumberSwift', '~> 1.4'Optional modules:
pod 'libPhoneNumberGeocoding', '~> 1.4'
pod 'libPhoneNumberShortNumber', '~> 1.4'Add this to your Cartfile:
github "iziz/libPhoneNumber-iOS"
Add the source files from the modules you need and link Contacts.framework for the core library.
Prefer libPhoneNumberSwift for new Swift code:
import libPhoneNumberSwift
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.
import libPhoneNumberSwift
let formatter = AsYouTypeFormatter(regionCode: "US")
formatter.inputDigit("6") // "6"
formatter.inputDigit("5") // "65"
formatter.inputDigit("0") // "650"
formatter.inputDigit("2") // "650-2"import libPhoneNumberSwift
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")import libPhoneNumberSwift
let phoneUtil = PhoneNumberUtility.shared
let geocoder = PhoneNumberGeocoder.shared
let number = try phoneUtil.parse("16502530000", defaultRegion: "US")
let description = geocoder.description(for: number, languageCode: "en")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);
}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"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 libPhoneNumberSwift unless it specifically needs Objective-C API details.
Phone number behavior is driven by Google's libphonenumber metadata. When metadata or upstream behavior changes, update this repository in a normal PR and include:
- The Google libphonenumber version or commit used.
- Main metadata changes.
- Geocoding metadata changes, if applicable.
- Upstream test parity results.
- Upstream API parity results.
- Local test results.
Useful commands:
swift scripts/checkUpstreamTestParity.swift --upstream-ref <version-or-ref>
swift scripts/checkUpstreamAPIParity.swift --upstream-ref <version-or-ref>
swift test
LC_ALL=ko_KR.UTF-8 LANG=ko_KR.UTF-8 swift test
swift build -c releaseFor the full maintenance workflow, see:
Run the metadata generator from the scripts directory:
cd scripts
./metadataGenerator.swift <libphonenumber-version> --prettyThis downloads metadata from Google's libphonenumber repository, updates the generated Objective-C metadata files from compact JSON, and writes pretty-printed generatedJSON files for review.
- Open
libPhoneNumber-GeocodingParserin Xcode. - Edit the run scheme arguments.
- Set the libphonenumber version.
- Set an output directory.
- Run the parser.
- Copy the generated
*.dbfiles intolibPhoneNumberGeocodingMetaData/GeocodingMetaData.bundle.
Before merging behavior, metadata, packaging, or API changes, run the relevant checks from docs/TESTING.md.
Common local checks:
swift test
LC_ALL=ko_KR.UTF-8 LANG=ko_KR.UTF-8 swift test
swift build -c release
git diff --checkFor Swift facade changes:
pod lib lint libPhoneNumberSwift.podspec --allow-warnings --include-podspecs='*.podspec'For Xcode schemes:
xcodebuild test -scheme libPhoneNumber -destination 'platform=iOS Simulator,name=iPhone 16'
xcodebuild test -scheme libPhoneNumberGeocoding -destination 'platform=iOS Simulator,name=iPhone 16'
xcodebuild test -scheme libPhoneNumberShortNumber -destination 'platform=iOS Simulator,name=iPhone 16'- Decide the next version:
- Patch for bug fixes.
- Minor for metadata updates or additive functionality.
- Major for breaking changes.
- Run the validation matrix.
- Lint the affected podspecs.
- Open a pull request with upstream version, parity results, and test results.
- Create a GitHub release after merge.
- Push updated podspecs.