Skip to content

Commit 42698ed

Browse files
authored
[Sessions] Add NetworkInfo abstraction over CoreTelephony helpers (#10399)
1 parent f7dea6e commit 42698ed

File tree

6 files changed

+165
-16
lines changed

6 files changed

+165
-16
lines changed

FirebaseSessions/Sources/ApplicationInfo.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ protocol ApplicationInfoProtocol {
3838
class ApplicationInfo: ApplicationInfoProtocol {
3939
let appID: String
4040

41-
init(appID: String) {
41+
private let networkInfo: NetworkInfoProtocol
42+
43+
init(appID: String, networkInfo: NetworkInfoProtocol = NetworkInfo()) {
4244
self.appID = appID
45+
self.networkInfo = networkInfo
4346
}
4447

4548
var bundleID: String {
@@ -58,6 +61,6 @@ class ApplicationInfo: ApplicationInfoProtocol {
5861
}
5962

6063
var mccMNC: String {
61-
return FIRSESGetMccMnc() ?? ""
64+
return FIRSESValidateMccMnc(networkInfo.mobileCountryCode, networkInfo.mobileNetworkCode) ?? ""
6265
}
6366
}

FirebaseSessions/Sources/NanoPB/FIRSESNanoPBHelpers.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,14 @@ BOOL FIRSESIsPBStringEqual(pb_bytes_array_t* _Nullable pbString, NSString* _Null
6565
/// @param data NSData that's expected
6666
BOOL FIRSESIsPBDataEqual(pb_bytes_array_t* _Nullable pbArray, NSData* _Nullable data);
6767

68+
/// Returns the cellular mobile country code (mnc) if CoreTelephony is supported, otherwise nil
69+
NSString* _Nullable FIRSESNetworkMobileCountryCode(void);
70+
71+
/// Returns the cellular mobile network code (mnc) if CoreTelephony is supported, otherwise nil
72+
NSString* _Nullable FIRSESNetworkMobileNetworkCode(void);
73+
6874
/// Returns the validated MccMnc if it is available, or nil if the device does not support telephone
69-
NSString* _Nullable FIRSESGetMccMnc(void);
75+
NSString* _Nullable FIRSESValidateMccMnc(NSString* _Nullable mcc, NSString* _Nullable mnc);
7076

7177
NS_ASSUME_NONNULL_END
7278

FirebaseSessions/Sources/NanoPB/FIRSESNanoPBHelpers.m

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,28 +135,49 @@ BOOL FIRSESIsPBDataEqual(pb_bytes_array_t *_Nullable pbArray, NSData *_Nullable
135135
});
136136
return networkInfo;
137137
}
138+
#endif
139+
140+
NSString *_Nullable FIRSESNetworkMobileCountryCode(void) {
141+
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
142+
CTTelephonyNetworkInfo *networkInfo = FIRSESNetworkInfo();
143+
CTCarrier *provider = networkInfo.subscriberCellularProvider;
144+
return provider.mobileCountryCode;
145+
#endif
146+
return nil;
147+
}
138148

139-
NSString *FIRSESValidatedMccMnc(NSString *mcc, NSString *mnc) {
140-
if ([mcc length] != 3 || [mnc length] < 2 || [mnc length] > 3) return nil;
149+
NSString *_Nullable FIRSESNetworkMobileNetworkCode(void) {
150+
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
151+
CTTelephonyNetworkInfo *networkInfo = FIRSESNetworkInfo();
152+
CTCarrier *provider = networkInfo.subscriberCellularProvider;
153+
return provider.mobileNetworkCode;
154+
#endif
155+
return nil;
156+
}
141157

158+
NSString *_Nullable FIRSESValidateMccMnc(NSString *_Nullable mcc, NSString *_Nullable mnc) {
159+
// These are both nil if the target does not support mobile connectivity
160+
if (mcc == nil && mnc == nil) {
161+
return nil;
162+
}
163+
164+
if (mcc.length != 3 || mnc.length < 2 || mnc.length > 3) {
165+
return nil;
166+
}
167+
168+
// If the resulting appended mcc + mnc contains characters that are not
169+
// decimal digits, return nil
142170
static NSCharacterSet *notDigits;
143171
static dispatch_once_t token;
144172
dispatch_once(&token, ^{
145173
notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
146174
});
147175
NSString *mccMnc = [mcc stringByAppendingString:mnc];
148-
if ([mccMnc rangeOfCharacterFromSet:notDigits].location != NSNotFound) return nil;
149-
return mccMnc;
150-
}
151-
#endif
176+
if ([mccMnc rangeOfCharacterFromSet:notDigits].location != NSNotFound) {
177+
return nil;
178+
}
152179

153-
NSString *_Nullable FIRSESGetMccMnc(void) {
154-
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
155-
CTTelephonyNetworkInfo *networkInfo = FIRSESNetworkInfo();
156-
CTCarrier *provider = networkInfo.subscriberCellularProvider;
157-
return FIRSESValidatedMccMnc(provider.mobileCountryCode, provider.mobileNetworkCode);
158-
#endif
159-
return nil;
180+
return mccMnc;
160181
}
161182

162183
NS_ASSUME_NONNULL_END
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// Copyright 2022 Google LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
import Foundation
17+
protocol NetworkInfoProtocol {
18+
var mobileCountryCode: String? { get }
19+
20+
var mobileNetworkCode: String? { get }
21+
}
22+
23+
class NetworkInfo: NetworkInfoProtocol {
24+
var mobileCountryCode: String? {
25+
return FIRSESNetworkMobileCountryCode()
26+
}
27+
28+
var mobileNetworkCode: String? {
29+
return FIRSESNetworkMobileNetworkCode()
30+
}
31+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//
2+
// Copyright 2022 Google LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
import XCTest
17+
18+
@testable import FirebaseSessions
19+
20+
class ApplicationInfoTests: XCTestCase {
21+
var appInfo: ApplicationInfo!
22+
var mockNetworkInfo: MockNetworkInfo!
23+
24+
override func setUp() {
25+
super.setUp()
26+
mockNetworkInfo = MockNetworkInfo()
27+
appInfo = ApplicationInfo(appID: "testAppID", networkInfo: mockNetworkInfo)
28+
}
29+
30+
func test_mccMNC_validatesCorrectly() {
31+
let expectations: [(mobileCountryCode: String, mobileNetworkCode: String, expected: String)] = [
32+
("310", "004", "310004"),
33+
("310", "01", "31001"),
34+
("001", "50", "00150"),
35+
]
36+
37+
expectations
38+
.forEach { (mobileCountryCode: String, mobileNetworkCode: String, expected: String) in
39+
mockNetworkInfo.mobileCountryCode = mobileCountryCode
40+
mockNetworkInfo.mobileNetworkCode = mobileNetworkCode
41+
42+
XCTAssertEqual(appInfo.mccMNC, expected)
43+
}
44+
}
45+
46+
func test_mccMNC_isEmptyWhenInvalid() {
47+
let expectations: [(mobileCountryCode: String?, mobileNetworkCode: String?)] = [
48+
("3100", "004"), // MCC too long
49+
("31", "01"), // MCC too short
50+
("310", "0512"), // MNC too long
51+
("L00", "003"), // MCC contains non-decimal characters
52+
("300", "00T"), // MNC contains non-decimal characters
53+
(nil, nil), // Handle nils gracefully
54+
(nil, "001"),
55+
("310", nil),
56+
]
57+
58+
expectations.forEach { (mobileCountryCode: String?, mobileNetworkCode: String?) in
59+
mockNetworkInfo.mobileCountryCode = mobileCountryCode
60+
mockNetworkInfo.mobileNetworkCode = mobileNetworkCode
61+
62+
XCTAssertEqual(appInfo.mccMNC, "")
63+
}
64+
}
65+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// Copyright 2022 Google LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
import Foundation
17+
18+
@testable import FirebaseSessions
19+
20+
class MockNetworkInfo: NetworkInfoProtocol {
21+
var mobileCountryCode: String?
22+
var mobileNetworkCode: String?
23+
}

0 commit comments

Comments
 (0)