Skip to content

Commit 881da8e

Browse files
committed
Release 1.6.0 Swift facade split
1 parent dac7652 commit 881da8e

34 files changed

Lines changed: 1677 additions & 475 deletions

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ jobs:
8585
pod lib lint libPhoneNumber-iOS.podspec --allow-warnings
8686
pod lib lint libPhoneNumberGeocoding.podspec --allow-warnings --include-podspecs='*.podspec'
8787
pod lib lint libPhoneNumberShortNumber.podspec --allow-warnings --include-podspecs='*.podspec'
88-
pod lib lint libPhoneNumberSwift.podspec --allow-warnings --include-podspecs='*.podspec'
88+
pod lib lint libPhoneNumber-iOS-SwiftCore.podspec --allow-warnings --include-podspecs='*.podspec'
89+
pod lib lint libPhoneNumber-iOS-SwiftGeocoding.podspec --allow-warnings --include-podspecs='*.podspec'
90+
pod lib lint libPhoneNumber-iOS-SwiftShortNumber.podspec --allow-warnings --include-podspecs='*.podspec'
91+
pod lib lint libPhoneNumber-iOS-SwiftUI.podspec --allow-warnings --include-podspecs='*.podspec'
92+
pod lib lint libPhoneNumber-iOS-Swift.podspec --allow-warnings --include-podspecs='*.podspec'
8993
9094
xcode-schemes:
9195
name: Xcode schemes

Package.swift

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ let package = Package(
2424
name: "libPhoneNumberShortNumber",
2525
targets: ["libPhoneNumberShortNumber"]
2626
),
27+
.library(
28+
name: "libPhoneNumberSwiftCore",
29+
targets: ["libPhoneNumberSwiftCore"]
30+
),
31+
.library(
32+
name: "libPhoneNumberSwiftGeocoding",
33+
targets: ["libPhoneNumberSwiftGeocoding"]
34+
),
35+
.library(
36+
name: "libPhoneNumberSwiftShortNumber",
37+
targets: ["libPhoneNumberSwiftShortNumber"]
38+
),
39+
.library(
40+
name: "libPhoneNumberSwiftUI",
41+
targets: ["libPhoneNumberSwiftUI"]
42+
),
2743
.library(
2844
name: "libPhoneNumberSwift",
2945
targets: ["libPhoneNumberSwift"]
@@ -128,20 +144,80 @@ let package = Package(
128144
path: "libPhoneNumberShortNumberTests"
129145
),
130146
.target(
131-
name: "libPhoneNumberSwift",
147+
name: "libPhoneNumberSwiftCore",
132148
dependencies: [
133149
"libPhoneNumber",
150+
],
151+
path: "libPhoneNumberSwiftCore"
152+
),
153+
.target(
154+
name: "libPhoneNumberSwiftGeocoding",
155+
dependencies: [
156+
"libPhoneNumberSwiftCore",
134157
"libPhoneNumberGeocoding",
158+
],
159+
path: "libPhoneNumberSwiftGeocoding"
160+
),
161+
.target(
162+
name: "libPhoneNumberSwiftShortNumber",
163+
dependencies: [
164+
"libPhoneNumberSwiftCore",
135165
"libPhoneNumberShortNumber",
136166
],
167+
path: "libPhoneNumberSwiftShortNumber"
168+
),
169+
.target(
170+
name: "libPhoneNumberSwift",
171+
dependencies: [
172+
"libPhoneNumberSwiftCore",
173+
"libPhoneNumberSwiftGeocoding",
174+
"libPhoneNumberSwiftShortNumber",
175+
],
137176
path: "libPhoneNumberSwift"
138177
),
178+
.target(
179+
name: "libPhoneNumberSwiftUI",
180+
dependencies: [
181+
"libPhoneNumberSwiftCore",
182+
],
183+
path: "libPhoneNumberSwiftUI"
184+
),
185+
.testTarget(
186+
name: "libPhoneNumberSwiftCoreTests",
187+
dependencies: [
188+
"libPhoneNumberSwiftCore",
189+
],
190+
path: "libPhoneNumberSwiftCoreTests"
191+
),
192+
.testTarget(
193+
name: "libPhoneNumberSwiftGeocodingTests",
194+
dependencies: [
195+
"libPhoneNumberSwiftCore",
196+
"libPhoneNumberSwiftGeocoding",
197+
],
198+
path: "libPhoneNumberSwiftGeocodingTests"
199+
),
200+
.testTarget(
201+
name: "libPhoneNumberSwiftShortNumberTests",
202+
dependencies: [
203+
"libPhoneNumberSwiftCore",
204+
"libPhoneNumberSwiftShortNumber",
205+
],
206+
path: "libPhoneNumberSwiftShortNumberTests"
207+
),
139208
.testTarget(
140209
name: "libPhoneNumberSwiftTests",
141210
dependencies: [
142211
"libPhoneNumberSwift",
143212
],
144213
path: "libPhoneNumberSwiftTests"
145214
),
215+
.testTarget(
216+
name: "libPhoneNumberSwiftUITests",
217+
dependencies: [
218+
"libPhoneNumberSwiftUI",
219+
],
220+
path: "libPhoneNumberSwiftUITests"
221+
),
146222
]
147223
)

README.md

Lines changed: 102 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ The project keeps the Objective-C core stable for existing apps while exposing a
1212

1313
| Product | Use when |
1414
| --- | --- |
15-
| `libPhoneNumberSwift` | You are writing new Swift code and want a native-feeling facade. |
15+
| `libPhoneNumberSwiftCore` | You are writing Swift code and only need parsing, formatting, validation, and as-you-type formatting. |
16+
| `libPhoneNumberSwiftGeocoding` | You need the Swift facade plus offline geocoding. |
17+
| `libPhoneNumberSwiftShortNumber` | You need the Swift facade plus emergency and short-code support. |
18+
| `libPhoneNumberSwiftUI` | You need a SwiftUI phone-number input component. |
19+
| `libPhoneNumberSwift` | You want the backwards-compatible Swift umbrella facade with every Swift module. |
1620
| `libPhoneNumber` | You need the stable Objective-C core API. |
1721
| `libPhoneNumberGeocoding` | You need offline region descriptions for phone numbers. |
1822
| `libPhoneNumberShortNumber` | You need emergency and short-code support. |
@@ -23,7 +27,21 @@ The project keeps the Objective-C core stable for existing apps while exposing a
2327

2428
Add this repository as a package dependency and select the products you need.
2529

26-
For most Swift apps, choose:
30+
For most Swift apps, choose the smallest Swift facade product:
31+
32+
```swift
33+
.product(name: "libPhoneNumberSwiftCore", package: "libPhoneNumber")
34+
```
35+
36+
Add optional Swift facade products only when needed:
37+
38+
```swift
39+
.product(name: "libPhoneNumberSwiftGeocoding", package: "libPhoneNumber")
40+
.product(name: "libPhoneNumberSwiftShortNumber", package: "libPhoneNumber")
41+
.product(name: "libPhoneNumberSwiftUI", package: "libPhoneNumber")
42+
```
43+
44+
Existing apps can keep using the umbrella product:
2745

2846
```swift
2947
.product(name: "libPhoneNumberSwift", package: "libPhoneNumber")
@@ -42,20 +60,34 @@ Use the Objective-C-compatible products directly if you need lower-level access:
4260
For Objective-C-compatible core APIs:
4361

4462
```ruby
45-
pod 'libPhoneNumber-iOS', '~> 1.5'
63+
pod 'libPhoneNumber-iOS', '~> 1.6'
64+
```
65+
66+
For the Swift-first core facade:
67+
68+
```ruby
69+
pod 'libPhoneNumber-iOS-SwiftCore', '~> 1.6'
70+
```
71+
72+
Optional Swift facade modules:
73+
74+
```ruby
75+
pod 'libPhoneNumber-iOS-SwiftGeocoding', '~> 1.6'
76+
pod 'libPhoneNumber-iOS-SwiftShortNumber', '~> 1.6'
77+
pod 'libPhoneNumber-iOS-SwiftUI', '~> 1.6'
4678
```
4779

48-
For the Swift-first facade:
80+
For the backwards-compatible Swift umbrella facade:
4981

5082
```ruby
51-
pod 'libPhoneNumberSwift', '~> 1.5'
83+
pod 'libPhoneNumber-iOS-Swift', '~> 1.6'
5284
```
5385

5486
Optional modules:
5587

5688
```ruby
57-
pod 'libPhoneNumberGeocoding', '~> 1.5'
58-
pod 'libPhoneNumberShortNumber', '~> 1.5'
89+
pod 'libPhoneNumberGeocoding', '~> 1.6'
90+
pod 'libPhoneNumberShortNumber', '~> 1.6'
5991
```
6092

6193
### Carthage
@@ -72,10 +104,10 @@ Add the source files from the modules you need and link `Contacts.framework` for
72104

73105
## Swift Quick Start
74106

75-
Prefer `libPhoneNumberSwift` for new Swift code:
107+
Prefer `libPhoneNumberSwiftCore` for new Swift code that only needs parsing, formatting, validation, and as-you-type formatting:
76108

77109
```swift
78-
import libPhoneNumberSwift
110+
import libPhoneNumberSwiftCore
79111

80112
let phoneUtil = PhoneNumberUtility.shared
81113
let phoneNumber = try phoneUtil.parse("01065431234", defaultRegion: "KR")
@@ -87,10 +119,21 @@ let numberType = phoneUtil.type(of: phoneNumber)
87119

88120
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.
89121

122+
For storage, concurrency boundaries, or API responses, use the immutable value wrapper:
123+
124+
```swift
125+
let value = try phoneUtil.value(from: "01065431234", defaultRegion: "KR").get()
126+
127+
value.e164
128+
value.regionCode
129+
value.nationalSignificantNumber
130+
value.type
131+
```
132+
90133
### As-You-Type Formatting
91134

92135
```swift
93-
import libPhoneNumberSwift
136+
import libPhoneNumberSwiftCore
94137

95138
let formatter = AsYouTypeFormatter(regionCode: "US")
96139

@@ -103,7 +146,8 @@ formatter.inputDigit("2") // "650-2"
103146
### Short Numbers
104147

105148
```swift
106-
import libPhoneNumberSwift
149+
import libPhoneNumberSwiftCore
150+
import libPhoneNumberSwiftShortNumber
107151

108152
let phoneUtil = PhoneNumberUtility.shared
109153
let shortUtil = ShortNumberUtility.shared
@@ -117,7 +161,8 @@ shortUtil.expectedCost(of: number, forRegion: "US")
117161
### Geocoding
118162

119163
```swift
120-
import libPhoneNumberSwift
164+
import libPhoneNumberSwiftCore
165+
import libPhoneNumberSwiftGeocoding
121166

122167
let phoneUtil = PhoneNumberUtility.shared
123168
let geocoder = PhoneNumberGeocoder.shared
@@ -126,6 +171,32 @@ let number = try phoneUtil.parse("16502530000", defaultRegion: "US")
126171
let description = geocoder.description(for: number, languageCode: "en")
127172
```
128173

174+
### SwiftUI Phone Input
175+
176+
```swift
177+
import SwiftUI
178+
import libPhoneNumberSwiftUI
179+
180+
struct PhoneForm: View {
181+
@State private var phoneNumber = ""
182+
@State private var e164: String?
183+
184+
var body: some View {
185+
PhoneNumberTextField(
186+
"Phone number",
187+
text: $phoneNumber,
188+
defaultRegion: "US",
189+
onStateChange: { state in
190+
e164 = state.e164
191+
},
192+
regionPicker: { region in
193+
Text(region)
194+
}
195+
)
196+
}
197+
}
198+
```
199+
129200
## Objective-C Usage
130201

131202
Use `NBPhoneNumberUtil` when integrating from Objective-C or when you need direct access to the core API:
@@ -187,7 +258,7 @@ For CocoaPods:
187258
#import "libPhoneNumber_iOS/NBPhoneNumber.h"
188259
```
189260

190-
New Swift code should prefer `libPhoneNumberSwift` unless it specifically needs Objective-C API details.
261+
New Swift code should prefer `libPhoneNumberSwiftCore` unless it specifically needs geocoding, short-number support, or Objective-C API details.
191262

192263
## Metadata And Upstream Parity
193264

@@ -203,6 +274,7 @@ Phone number behavior is driven by Google's libphonenumber metadata. When metada
203274
Useful commands:
204275

205276
```bash
277+
swift scripts/checkMetadataFreshness.swift
206278
swift scripts/checkUpstreamTestParity.swift --upstream-ref <version-or-ref>
207279
swift scripts/checkUpstreamAPIParity.swift --upstream-ref <version-or-ref>
208280
swift test
@@ -213,6 +285,8 @@ swift build -c release
213285
For the full maintenance workflow, see:
214286

215287
- [Upstream parity guide](docs/UPSTREAM_PARITY.md)
288+
- [Metadata patch policy](docs/METADATA_PATCH_POLICY.md)
289+
- [Package size options](docs/PACKAGE_SIZE_OPTIONS.md)
216290
- [Testing guide](docs/TESTING.md)
217291

218292
## Updating Metadata
@@ -246,6 +320,16 @@ swift scripts/updateGeocodingMetadata.swift --source /tmp/libphonenumber --outpu
246320

247321
Use `--output` to inspect generated databases before replacing the checked-in bundle. Use `--source` when you already have a local Google libphonenumber checkout or an extracted `resources/geocoding` directory.
248322

323+
### Freshness Check
324+
325+
Generate a current-vs-upstream metadata freshness summary and issue/PR text candidates:
326+
327+
```bash
328+
swift scripts/checkMetadataFreshness.swift --output .build/metadata-freshness
329+
```
330+
331+
The script writes review artifacts only. It does not modify checked-in metadata.
332+
249333
## Validation
250334

251335
Before merging behavior, metadata, packaging, or API changes, run the relevant checks from [docs/TESTING.md](docs/TESTING.md).
@@ -263,7 +347,11 @@ git diff --check
263347
For Swift facade changes:
264348

265349
```bash
266-
pod lib lint libPhoneNumberSwift.podspec --allow-warnings --include-podspecs='*.podspec'
350+
pod lib lint libPhoneNumber-iOS-SwiftCore.podspec --allow-warnings --include-podspecs='*.podspec'
351+
pod lib lint libPhoneNumber-iOS-SwiftGeocoding.podspec --allow-warnings --include-podspecs='*.podspec'
352+
pod lib lint libPhoneNumber-iOS-SwiftShortNumber.podspec --allow-warnings --include-podspecs='*.podspec'
353+
pod lib lint libPhoneNumber-iOS-SwiftUI.podspec --allow-warnings --include-podspecs='*.podspec'
354+
pod lib lint libPhoneNumber-iOS-Swift.podspec --allow-warnings --include-podspecs='*.podspec'
267355
```
268356

269357
For Xcode schemes:

docs/CARRIER_TIMEZONE_METADATA.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Carrier And Timezone Metadata Evaluation
2+
3+
Google libphonenumber ships carrier and timezone metadata outside the JavaScript metadata currently mirrored by this project. Adding those datasets could differentiate this library for global and enterprise apps, but it should be treated as a separate feature area rather than folded into the core parser.
4+
5+
## Recommended Direction
6+
7+
- Keep carrier and timezone metadata out of `libPhoneNumberSwiftCore`.
8+
- Add separate Objective-C metadata bundles and Swift facade modules only if there is confirmed product demand.
9+
- Prefer opt-in packages:
10+
- `libPhoneNumberCarrier`
11+
- `libPhoneNumberTimezone`
12+
- `libPhoneNumberSwiftCarrier`
13+
- `libPhoneNumberSwiftTimezone`
14+
- Measure bundle size before adding checked-in metadata.
15+
16+
## Required Work Before Implementation
17+
18+
1. Identify the exact upstream metadata source files and license implications.
19+
2. Build deterministic generators for carrier and timezone metadata.
20+
3. Add tests against upstream examples.
21+
4. Add package-size reporting to the release checklist.
22+
5. Decide whether APIs return localized display names, stable identifiers, or both.
23+
24+
## API Shape To Consider
25+
26+
```swift
27+
let carrier = PhoneNumberCarrierMapper.shared.name(for: number, languageCode: "en")
28+
let timeZones = PhoneNumberTimeZoneMapper.shared.timeZones(for: number)
29+
```
30+
31+
These APIs should delegate lookup behavior to generated metadata and should not add parsing rules outside the Objective-C core.

0 commit comments

Comments
 (0)