From 01d98357c687f4ba1e325e0cb2069db1091c24c5 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 12:35:59 +1100 Subject: [PATCH 01/10] Extract `defaultUserAgent` method to Swift --- WordPress/Classes/Utility/WPUserAgent.m | 18 +------- WordPress/Classes/Utility/WPUserAgent.swift | 32 +++++++++++++ WordPress/WordPress.xcodeproj/project.pbxproj | 4 ++ .../WordPressTest/WPUserAgentTests.swift | 46 +++++++++++++++++++ 4 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 WordPress/WordPressTest/WPUserAgentTests.swift diff --git a/WordPress/Classes/Utility/WPUserAgent.m b/WordPress/Classes/Utility/WPUserAgent.m index dabac750fc03..c7730af271f1 100644 --- a/WordPress/Classes/Utility/WPUserAgent.m +++ b/WordPress/Classes/Utility/WPUserAgent.m @@ -9,23 +9,7 @@ @implementation WPUserAgent + (NSString *)defaultUserAgent { - static NSString * _defaultUserAgent; - static dispatch_once_t _onceToken; - dispatch_once(&_onceToken, ^{ - NSDictionary * registrationDomain = [[UserPersistentStoreFactory userDefaultsInstance] volatileDomainForName:NSRegistrationDomain]; - NSString *storeCurrentUA = [registrationDomain objectForKey:WPUserAgentKeyUserAgent]; - [[UserPersistentStoreFactory userDefaultsInstance] registerDefaults:@{WPUserAgentKeyUserAgent: @(0)}]; - - _defaultUserAgent = [self webViewUserAgent]; - - if (storeCurrentUA) { - [[UserPersistentStoreFactory userDefaultsInstance] registerDefaults:@{WPUserAgentKeyUserAgent: storeCurrentUA}]; - } - }); - NSAssert(_defaultUserAgent != nil, @"User agent shouldn't be nil"); - NSAssert([_defaultUserAgent length] > 0, @"User agent shouldn't be empty"); - - return _defaultUserAgent; + return [TemporaryWPUserAgent defaultUserAgentWithUserDefaults:[UserPersistentStoreFactory userDefaultsInstance]]; } + (NSString *)wordPressUserAgent diff --git a/WordPress/Classes/Utility/WPUserAgent.swift b/WordPress/Classes/Utility/WPUserAgent.swift index c86e3d9161f5..0977d468f43e 100644 --- a/WordPress/Classes/Utility/WPUserAgent.swift +++ b/WordPress/Classes/Utility/WPUserAgent.swift @@ -1,4 +1,36 @@ import Foundation +import WebKit +import WordPressShared + +// TODO: We'll implement this one step at a time then renamed it to WPUserAgent +@objc +public class TemporaryWPUserAgent: NSObject { + + public static let userAgentKey = "UserAgent" + + @objc + public static func defaultUserAgent(userDefaults: UserDefaults) -> String { + // FIXME: What's the point of reading from user defaults then returning a possibly different value? + // See original Objective-C implementation at + // https://github.com/wordpress-mobile/WordPress-iOS/blob/a6eaa7aa8acb50828449df2d3fccaa50d7def821/WordPress/Classes/Utility/WPUserAgent.m#L10-L29 + + // 1. Extract current stored user agent + let registrationDomain = userDefaults.volatileDomain(forName: UserDefaults.registrationDomain) + let storedUserAgent = registrationDomain[userAgentKey] as? String + + // 2. Flush stored user agent + userDefaults.register(defaults: [userAgentKey: ""]) + + // 3. Reset the stored user agent if there was one in the first place (why??) + if let storedUserAgent { + userDefaults.register(defaults: [userAgentKey: storedUserAgent]) + } + + let userAgent = WPUserAgent.webViewUserAgent + assert(!userAgent.isEmpty, "User agent should not be empty") + return userAgent + } +} extension WPUserAgent { diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index e04de3b87e25..28e4e3053a8f 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -331,6 +331,7 @@ 3236F7A124B61B950088E8F3 /* ReaderInterestsDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3236F7A024B61B950088E8F3 /* ReaderInterestsDataSourceTests.swift */; }; 323F8F3023A22C4C000BA49C /* SiteCreationRotatingMessageViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C6CDDA23A1FF0D002556FF /* SiteCreationRotatingMessageViewTests.swift */; }; 374CB16215B93C0800DD0EBC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */; }; + 3F03CD1C2D83BDA20047508B /* WPUserAgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */; }; 3F1B66A323A2F54B0075F09E /* ReaderReblogActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */; }; 3F28CEA52A4ABB8800B79686 /* PrivacySettingsAnalyticsTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F28CEA42A4ABB8800B79686 /* PrivacySettingsAnalyticsTrackerTests.swift */; }; 3F28CEA92A4ACB1000B79686 /* AnalyticsEventTrackingSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F28CEA82A4ACB1000B79686 /* AnalyticsEventTrackingSpy.swift */; }; @@ -2139,6 +2140,7 @@ 3236F7A024B61B950088E8F3 /* ReaderInterestsDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderInterestsDataSourceTests.swift; sourceTree = ""; }; 32C6CDDA23A1FF0D002556FF /* SiteCreationRotatingMessageViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationRotatingMessageViewTests.swift; sourceTree = ""; }; 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WPUserAgentTests.swift; sourceTree = ""; }; 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderReblogActionTests.swift; sourceTree = ""; }; 3F28CEA42A4ABB8800B79686 /* PrivacySettingsAnalyticsTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsAnalyticsTrackerTests.swift; sourceTree = ""; }; 3F28CEA82A4ACB1000B79686 /* AnalyticsEventTrackingSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventTrackingSpy.swift; sourceTree = ""; }; @@ -5588,6 +5590,7 @@ 93A379EB19FFBF7900415023 /* KeychainTest.m */, 5948AD101AB73D19006E8882 /* WPAppAnalyticsTests.m */, 5981FE041AB8A89A0009E080 /* WPUserAgentTests.m */, + 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */, 82301B8E1E787420009C9C4E /* AppRatingUtilityTests.swift */, F551E7F623FC9A5C00751212 /* Collection+RotateTests.swift */, E180BD4B1FB462FF00D0D781 /* CookieJarTests.swift */, @@ -9327,6 +9330,7 @@ 436D5655212209D600CEAA33 /* RegisterDomainDetailsServiceProxyMock.swift in Sources */, F1450CF92437EEBB00A28BFE /* MediaRequestAuthenticatorTests.swift in Sources */, FE6BB1462932289B001E5F7A /* ContentMigrationCoordinatorTests.swift in Sources */, + 3F03CD1C2D83BDA20047508B /* WPUserAgentTests.swift in Sources */, FEFA6AC62A86824A004EE5E6 /* PostHelperJetpackSocialTests.swift in Sources */, 0C391E642A312DB20040EA91 /* BlazeCampaignViewModelTests.swift in Sources */, D821C817210036D9002ED995 /* ActivityContentFactoryTests.swift in Sources */, diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/WordPress/WordPressTest/WPUserAgentTests.swift new file mode 100644 index 000000000000..3061b3f5fda4 --- /dev/null +++ b/WordPress/WordPressTest/WPUserAgentTests.swift @@ -0,0 +1,46 @@ +import Testing +import WebKit +@testable import WordPress + +class WPWPUserAgentTests { + + @Test + func wordPressUserAgentValue() throws { + let appVersion = try #require(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) + let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: .standard) + let expectedUserAgent = String.init(format: "%@ wp-iphone/%@", defaultUserAgent, appVersion) + + #expect(WPUserAgent.wordPress() == expectedUserAgent) + } + + @Test + func usesWordPressUserAgentInWebViews() throws { + if #available(iOS 17, *) { // #available cannot go as an argument in @Test(.enabled(if: ..)) + print("In iOS 17, WKWebView no longer reads User Agent from UserDefaults. Skipping while working on an alternative setup.") + return + } + + let userDefaults = UserDefaults.standard + let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: userDefaults) + let wordPressUserAgent = WPUserAgent.wordPress() + + // FIXME: Is this necessary? + // See original implementation at + // https://github.com/wordpress-mobile/WordPress-iOS/blob/a6eaa7aa8acb50828449df2d3fccaa50d7def821/WordPress/WordPressTest/WPUserAgentTests.m#L57-L75 + userDefaults.removeObject(forKey: TemporaryWPUserAgent.userAgentKey) + userDefaults.register(defaults: [TemporaryWPUserAgent.userAgentKey: defaultUserAgent]) + + WPUserAgent.useWordPressInWebViews() + + #expect(try currentUserAgent(userDefaults: userDefaults) == wordPressUserAgent) + #expect(try currentUserAgentFromWebView() == wordPressUserAgent) + } + + func currentUserAgent(userDefaults: UserDefaults) throws -> String { + try #require(userDefaults.object(forKey: TemporaryWPUserAgent.userAgentKey) as? String) + } + + func currentUserAgentFromWebView() throws -> String { + try #require(WKWebView.userAgent()) + } +} From dd814b4230dca1b8afd558dc56c1cae38772ab39 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 13:05:54 +1100 Subject: [PATCH 02/10] Extract `wordPressUserAgent` to Swift --- WordPress/Classes/Utility/WPUserAgent.m | 9 +-------- WordPress/Classes/Utility/WPUserAgent.swift | 11 +++++++++++ .../WordPressTest/WPUserAgentTests.swift | 19 ++++++++++++++++--- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/WordPress/Classes/Utility/WPUserAgent.m b/WordPress/Classes/Utility/WPUserAgent.m index c7730af271f1..865c37e632fd 100644 --- a/WordPress/Classes/Utility/WPUserAgent.m +++ b/WordPress/Classes/Utility/WPUserAgent.m @@ -14,14 +14,7 @@ + (NSString *)defaultUserAgent + (NSString *)wordPressUserAgent { - static NSString * _wordPressUserAgent; - if (_wordPressUserAgent == nil) { - NSString *defaultUA = [self defaultUserAgent]; - NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; - _wordPressUserAgent = [NSString stringWithFormat:@"%@ wp-iphone/%@", defaultUA, appVersion]; - } - - return _wordPressUserAgent; + return [TemporaryWPUserAgent wordPressUserAgentWithUserDefaults:[UserPersistentStoreFactory userDefaultsInstance] bundle:[NSBundle mainBundle]]; } + (void)useWordPressUserAgentInWebViews diff --git a/WordPress/Classes/Utility/WPUserAgent.swift b/WordPress/Classes/Utility/WPUserAgent.swift index 0977d468f43e..74b6ccb39687 100644 --- a/WordPress/Classes/Utility/WPUserAgent.swift +++ b/WordPress/Classes/Utility/WPUserAgent.swift @@ -30,6 +30,17 @@ public class TemporaryWPUserAgent: NSObject { assert(!userAgent.isEmpty, "User agent should not be empty") return userAgent } + + // The original impelmentation had logic to only read this once if not nil. + // But why? The performance hit should be negligible. + // + // See original implementation at + // https://github.com/wordpress-mobile/WordPress-iOS/blob/a6eaa7aa8acb50828449df2d3fccaa50d7def821/WordPress/Classes/Utility/WPUserAgent.m#L31-L41 + @objc + public static func wordPressUserAgent(userDefaults: UserDefaults, bundle: Bundle = .main) -> String { + let appVersion = bundle.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown" + return "\(defaultUserAgent(userDefaults: userDefaults)) wp-iphone/\(appVersion)" + } } extension WPUserAgent { diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/WordPress/WordPressTest/WPUserAgentTests.swift index 3061b3f5fda4..110108ff4038 100644 --- a/WordPress/WordPressTest/WPUserAgentTests.swift +++ b/WordPress/WordPressTest/WPUserAgentTests.swift @@ -6,11 +6,12 @@ class WPWPUserAgentTests { @Test func wordPressUserAgentValue() throws { + let userDefaults = UserDefaults.standard let appVersion = try #require(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) - let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: .standard) + let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: userDefaults) let expectedUserAgent = String.init(format: "%@ wp-iphone/%@", defaultUserAgent, appVersion) - #expect(WPUserAgent.wordPress() == expectedUserAgent) + #expect(TemporaryWPUserAgent.wordPressUserAgent(userDefaults: userDefaults) == expectedUserAgent) } @Test @@ -22,7 +23,7 @@ class WPWPUserAgentTests { let userDefaults = UserDefaults.standard let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: userDefaults) - let wordPressUserAgent = WPUserAgent.wordPress() + let wordPressUserAgent = TemporaryWPUserAgent.wordPressUserAgent(userDefaults: userDefaults) // FIXME: Is this necessary? // See original implementation at @@ -36,6 +37,18 @@ class WPWPUserAgentTests { #expect(try currentUserAgentFromWebView() == wordPressUserAgent) } + // FIXME: Is there even a point in testing for no throws when the method does not throw? + // See original implementation at + // https://github.com/wordpress-mobile/WordPress-iOS/blob/a6eaa7aa8acb50828449df2d3fccaa50d7def821/WordPress/WordPressTest/WPUserAgentTests.m#L102-L107 + @Test + func accessingWordPressUserAgentOutsideMainThread() { + #expect(throws: Never.self, "Accessing outside the main thread should work") { + DispatchQueue.global(qos: .background).sync { + TemporaryWPUserAgent.wordPressUserAgent(userDefaults: .standard) + } + } + } + func currentUserAgent(userDefaults: UserDefaults) throws -> String { try #require(userDefaults.object(forKey: TemporaryWPUserAgent.userAgentKey) as? String) } From 23eeeac25d9206310e25c73642f8eb79e2655f26 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 13:38:47 +1100 Subject: [PATCH 03/10] Port remaining WPUserAgent tests to Swift --- .../WordPressTest/WPUserAgentTests.swift | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/WordPress/WordPressTest/WPUserAgentTests.swift index 110108ff4038..2fd697077053 100644 --- a/WordPress/WordPressTest/WPUserAgentTests.swift +++ b/WordPress/WordPressTest/WPUserAgentTests.swift @@ -1,9 +1,23 @@ +import Foundation import Testing import WebKit @testable import WordPress class WPWPUserAgentTests { + @Test + func userAgentFormat() throws { + let userAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: .standard) + + #expect( + try webKitUserAgentRegExp().numberOfMatches( + in: userAgent, + options: [], + range: NSRange(location: 0, length: userAgent.utf16.count) + ) == 1 + ) + } + @Test func wordPressUserAgentValue() throws { let userDefaults = UserDefaults.standard @@ -56,4 +70,45 @@ class WPWPUserAgentTests { func currentUserAgentFromWebView() throws -> String { try #require(WKWebView.userAgent()) } + + func webKitUserAgentRegExp() throws -> NSRegularExpression { + try NSRegularExpression( + pattern: "^Mozilla/5\\.0 \\([a-zA-Z]+; CPU [\\sa-zA-Z]+ [_0-9]+ like Mac OS X\\) AppleWebKit/605\\.1\\.15 \\(KHTML, like Gecko\\) Mobile/15E148$" + ) + } + + // MARK: - Tests for underlying assumptions + + @Test + func registerInUserDefaultsAdds() throws { + let userDefaults = UserDefaults.standard + let domainName = try #require(userDefaults.volatileDomainNames.first) + let originalDomain = userDefaults.volatileDomain(forName: domainName) + + userDefaults.register(defaults: ["test-key": 0]) + + let updatedDomain = userDefaults.volatileDomain(forName: domainName) + + // From the docs: + // Registered defaults are never stored between runs of an application, and are visible only to the application that registers them + // + // So we expect the count to be +1 + #expect(updatedDomain.count == originalDomain.count + 1) + } + + // If this test fails, it may mean `WKWebView` uses a user agent with an unexpected format (see `webKitUserAgentRegExp`) + // and we may need to adjust our implementation to match the new `WKWebView` user agent. + @Test + func testWebKitUserAgentFormat() throws { + let regExp = try webKitUserAgentRegExp() + // Please note: WKWebView's user agent may be different on different test device types. + let userAgent = try currentUserAgentFromWebView() + #expect( + try webKitUserAgentRegExp().numberOfMatches( + in: userAgent, + options: [], + range: NSRange(location: 0, length: userAgent.utf16.count) + ) == 1 + ) + } } From d5bbce2e439fbc70194b60fa8bb18710bda793c6 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 13:49:34 +1100 Subject: [PATCH 04/10] Port `useWordPressUserAgentInWebViews` to Swift --- WordPress/Classes/Utility/WPUserAgent.m | 14 +------------- WordPress/Classes/Utility/WPUserAgent.swift | 14 ++++++++++++++ WordPress/WordPressTest/WPUserAgentTests.swift | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/WordPress/Classes/Utility/WPUserAgent.m b/WordPress/Classes/Utility/WPUserAgent.m index 865c37e632fd..2f6bee1d82df 100644 --- a/WordPress/Classes/Utility/WPUserAgent.m +++ b/WordPress/Classes/Utility/WPUserAgent.m @@ -19,19 +19,7 @@ + (NSString *)wordPressUserAgent + (void)useWordPressUserAgentInWebViews { - // Cleanup unused NSUserDefaults keys from older WPUserAgent implementation - [[UserPersistentStoreFactory userDefaultsInstance] removeObjectForKey:@"DefaultUserAgent"]; - [[UserPersistentStoreFactory userDefaultsInstance] removeObjectForKey:@"AppUserAgent"]; - - NSString *userAgent = [self wordPressUserAgent]; - - NSParameterAssert([userAgent isKindOfClass:[NSString class]]); - - NSDictionary *dictionary = @{WPUserAgentKeyUserAgent: userAgent}; - // We have to call registerDefaults else the change isn't picked up by WKWebViews. - [[UserPersistentStoreFactory userDefaultsInstance] registerDefaults:dictionary]; - - DDLogVerbose(@"User-Agent set to: %@", userAgent); + [TemporaryWPUserAgent useWordPressUserAgentInWebViewsWithUserDefaults:[UserPersistentStoreFactory userDefaultsInstance]]; } @end diff --git a/WordPress/Classes/Utility/WPUserAgent.swift b/WordPress/Classes/Utility/WPUserAgent.swift index 74b6ccb39687..ddad53bef8c8 100644 --- a/WordPress/Classes/Utility/WPUserAgent.swift +++ b/WordPress/Classes/Utility/WPUserAgent.swift @@ -41,6 +41,20 @@ public class TemporaryWPUserAgent: NSObject { let appVersion = bundle.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown" return "\(defaultUserAgent(userDefaults: userDefaults)) wp-iphone/\(appVersion)" } + + @objc + public static func useWordPressUserAgentInWebViews(userDefaults: UserDefaults) { + // Cleanup unused UserDefaults keys from older WPUserAgent implementation + // FIXME: How old are those older implementations? Can we remove this code because "old enough"? + userDefaults.removeObject(forKey: "DefaultUserAgent") + userDefaults.removeObject(forKey: "AppUserAgent") + + let userAgent = wordPressUserAgent(userDefaults: userDefaults) + + userDefaults.register(defaults: [userAgentKey: userAgent]) + + DDLogVerbose("User-Agent set to \(userAgent)") + } } extension WPUserAgent { diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/WordPress/WordPressTest/WPUserAgentTests.swift index 2fd697077053..b912ba386498 100644 --- a/WordPress/WordPressTest/WPUserAgentTests.swift +++ b/WordPress/WordPressTest/WPUserAgentTests.swift @@ -45,7 +45,7 @@ class WPWPUserAgentTests { userDefaults.removeObject(forKey: TemporaryWPUserAgent.userAgentKey) userDefaults.register(defaults: [TemporaryWPUserAgent.userAgentKey: defaultUserAgent]) - WPUserAgent.useWordPressInWebViews() + TemporaryWPUserAgent.useWordPressUserAgentInWebViews(userDefaults: userDefaults) #expect(try currentUserAgent(userDefaults: userDefaults) == wordPressUserAgent) #expect(try currentUserAgentFromWebView() == wordPressUserAgent) From 24c359af1d793103c9dd93828900d00dbf1b8438 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 13:51:36 +1100 Subject: [PATCH 05/10] Address threading issue in tests when calling WebKit --- WordPress/WordPressTest/WPUserAgentTests.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/WordPress/WordPressTest/WPUserAgentTests.swift index b912ba386498..7d8ff063ea91 100644 --- a/WordPress/WordPressTest/WPUserAgentTests.swift +++ b/WordPress/WordPressTest/WPUserAgentTests.swift @@ -28,7 +28,7 @@ class WPWPUserAgentTests { #expect(TemporaryWPUserAgent.wordPressUserAgent(userDefaults: userDefaults) == expectedUserAgent) } - @Test + @Test @MainActor func usesWordPressUserAgentInWebViews() throws { if #available(iOS 17, *) { // #available cannot go as an argument in @Test(.enabled(if: ..)) print("In iOS 17, WKWebView no longer reads User Agent from UserDefaults. Skipping while working on an alternative setup.") @@ -67,6 +67,7 @@ class WPWPUserAgentTests { try #require(userDefaults.object(forKey: TemporaryWPUserAgent.userAgentKey) as? String) } + @MainActor func currentUserAgentFromWebView() throws -> String { try #require(WKWebView.userAgent()) } @@ -98,7 +99,7 @@ class WPWPUserAgentTests { // If this test fails, it may mean `WKWebView` uses a user agent with an unexpected format (see `webKitUserAgentRegExp`) // and we may need to adjust our implementation to match the new `WKWebView` user agent. - @Test + @Test @MainActor func testWebKitUserAgentFormat() throws { let regExp = try webKitUserAgentRegExp() // Please note: WKWebView's user agent may be different on different test device types. From cf73076f7401f30cad45dcdd25fb9ac2303496b6 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 14:15:25 +1100 Subject: [PATCH 06/10] Replace Objective-C `WPUserAgent` with Swift one Notice we implemented it one step at a time and used it in the Objective-C implementation all along to ensure the tests passed. Now that everything is green, we can swap at the consuming code level. --- WordPress/Classes/Models/Blog/Blog.m | 1 - .../System/WordPress-Bridging-Header.h | 2 - .../Analytics/WPAnalyticsTrackerWPCom.m | 2 +- WordPress/Classes/Utility/WPUserAgent.h | 24 ---- WordPress/Classes/Utility/WPUserAgent.m | 25 ---- WordPress/Classes/Utility/WPUserAgent.swift | 28 ++++- .../WebViewController/WPWebViewController.m | 1 - WordPress/WordPress.xcodeproj/project.pbxproj | 4 - WordPress/WordPressTest/WPUserAgentTests.m | 118 ------------------ .../WordPressTest/WPUserAgentTests.swift | 20 +-- 10 files changed, 33 insertions(+), 192 deletions(-) delete mode 100644 WordPress/Classes/Utility/WPUserAgent.h delete mode 100644 WordPress/Classes/Utility/WPUserAgent.m delete mode 100644 WordPress/WordPressTest/WPUserAgentTests.m diff --git a/WordPress/Classes/Models/Blog/Blog.m b/WordPress/Classes/Models/Blog/Blog.m index 00af1b831922..1884459def73 100644 --- a/WordPress/Classes/Models/Blog/Blog.m +++ b/WordPress/Classes/Models/Blog/Blog.m @@ -2,7 +2,6 @@ #import "WPAccount.h" #import "AccountService.h" @import WordPressDataObjC; -#import "WPUserAgent.h" #import "WordPress-Swift.h" @import SFHFKeychainUtils; diff --git a/WordPress/Classes/System/WordPress-Bridging-Header.h b/WordPress/Classes/System/WordPress-Bridging-Header.h index a735289d6c2e..16a40febb0f3 100644 --- a/WordPress/Classes/System/WordPress-Bridging-Header.h +++ b/WordPress/Classes/System/WordPress-Bridging-Header.h @@ -76,10 +76,8 @@ #import "WPStyleGuide+Pages.h" #import "WPStyleGuide+WebView.h" #import "WPTableViewHandler.h" -#import "WPUserAgent.h" #import "WPWebViewController.h" #import "WPTabBarController.h" -#import "WPUserAgent.h" #import "WPLogger.h" #import "WPException.h" diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsTrackerWPCom.m b/WordPress/Classes/Utility/Analytics/WPAnalyticsTrackerWPCom.m index ba0f1dd911f1..44465d4b1aad 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsTrackerWPCom.m +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsTrackerWPCom.m @@ -1,5 +1,5 @@ #import "WPAnalyticsTrackerWPCom.h" -#import "WPUserAgent.h" +#import "WordPress-Swift.h" #import "Constants.h" @import WordPressShared; diff --git a/WordPress/Classes/Utility/WPUserAgent.h b/WordPress/Classes/Utility/WPUserAgent.h deleted file mode 100644 index 51cf41e7331f..000000000000 --- a/WordPress/Classes/Utility/WPUserAgent.h +++ /dev/null @@ -1,24 +0,0 @@ -#import - -/** - * @class WPUserAgent - * @brief Takes care of the user-agent logic for WPiOS. - */ -@interface WPUserAgent : NSObject - -/** - * @brief Default User-Agent header. - */ -+ (NSString *)defaultUserAgent; - -/** - * @brief WordPress custom User-Agent header. - */ -+ (NSString *)wordPressUserAgent; - -/** - * @brief Sets User-Agent header of all web views to be the WordPress one. - */ -+ (void)useWordPressUserAgentInWebViews; - -@end diff --git a/WordPress/Classes/Utility/WPUserAgent.m b/WordPress/Classes/Utility/WPUserAgent.m deleted file mode 100644 index 2f6bee1d82df..000000000000 --- a/WordPress/Classes/Utility/WPUserAgent.m +++ /dev/null @@ -1,25 +0,0 @@ -#import "WPUserAgent.h" -#import "WordPress-Swift.h" - -@import WebKit; - -static NSString* const WPUserAgentKeyUserAgent = @"UserAgent"; - -@implementation WPUserAgent - -+ (NSString *)defaultUserAgent -{ - return [TemporaryWPUserAgent defaultUserAgentWithUserDefaults:[UserPersistentStoreFactory userDefaultsInstance]]; -} - -+ (NSString *)wordPressUserAgent -{ - return [TemporaryWPUserAgent wordPressUserAgentWithUserDefaults:[UserPersistentStoreFactory userDefaultsInstance] bundle:[NSBundle mainBundle]]; -} - -+ (void)useWordPressUserAgentInWebViews -{ - [TemporaryWPUserAgent useWordPressUserAgentInWebViewsWithUserDefaults:[UserPersistentStoreFactory userDefaultsInstance]]; -} - -@end diff --git a/WordPress/Classes/Utility/WPUserAgent.swift b/WordPress/Classes/Utility/WPUserAgent.swift index ddad53bef8c8..e56b16f90f9c 100644 --- a/WordPress/Classes/Utility/WPUserAgent.swift +++ b/WordPress/Classes/Utility/WPUserAgent.swift @@ -2,9 +2,8 @@ import Foundation import WebKit import WordPressShared -// TODO: We'll implement this one step at a time then renamed it to WPUserAgent @objc -public class TemporaryWPUserAgent: NSObject { +public class WPUserAgent: NSObject { public static let userAgentKey = "UserAgent" @@ -43,7 +42,7 @@ public class TemporaryWPUserAgent: NSObject { } @objc - public static func useWordPressUserAgentInWebViews(userDefaults: UserDefaults) { + public static func useWordPressInWebViews(userDefaults: UserDefaults) { // Cleanup unused UserDefaults keys from older WPUserAgent implementation // FIXME: How old are those older implementations? Can we remove this code because "old enough"? userDefaults.removeObject(forKey: "DefaultUserAgent") @@ -55,9 +54,6 @@ public class TemporaryWPUserAgent: NSObject { DDLogVerbose("User-Agent set to \(userAgent)") } -} - -extension WPUserAgent { /// Returns a user agent string similar to (but may not exactly match) the one used in `WKWebView`. @objc static var webViewUserAgent: String { @@ -98,3 +94,23 @@ extension WPUserAgent { return "Mozilla/5.0 (\(deviceModel); CPU \(osName) \(osVersion) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" } } + +public extension WPUserAgent { + + private static let userDefaults = UserPersistentStoreFactory.userDefaultsInstance() + + @objc + static func defaultUserAgent() -> String { + defaultUserAgent(userDefaults: userDefaults) + } + + @objc(wordPressUserAgent) + static func wordPress() -> String { + wordPressUserAgent(userDefaults: userDefaults) + } + + @objc + static func useWordPressInWebViews() { + useWordPressInWebViews(userDefaults: userDefaults) + } +} diff --git a/WordPress/Classes/Utility/WebViewController/WPWebViewController.m b/WordPress/Classes/Utility/WebViewController/WPWebViewController.m index 5b61051a5a89..2b182a572dd8 100644 --- a/WordPress/Classes/Utility/WebViewController/WPWebViewController.m +++ b/WordPress/Classes/Utility/WebViewController/WPWebViewController.m @@ -1,7 +1,6 @@ #import "WPWebViewController.h" #import "ReachabilityUtils.h" #import "WPActivityDefaults.h" -#import "WPUserAgent.h" #import "Constants.h" #import "WPError.h" #import "WPStyleGuide+WebView.h" diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 28e4e3053a8f..5fa011163628 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -675,7 +675,6 @@ 57B71D4E230DB5F200789A68 /* BlogBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57B71D4D230DB5F200789A68 /* BlogBuilder.swift */; }; 5948AD111AB73D19006E8882 /* WPAppAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5948AD101AB73D19006E8882 /* WPAppAnalyticsTests.m */; }; 5960967F1CF7959300848496 /* PostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5960967E1CF7959300848496 /* PostTests.swift */; }; - 5981FE051AB8A89A0009E080 /* WPUserAgentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5981FE041AB8A89A0009E080 /* WPUserAgentTests.m */; }; 59B48B621B99E132008EBB84 /* JSONObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59B48B611B99E132008EBB84 /* JSONObject.swift */; }; 59ECF87B1CB7061D00E68F25 /* PostSharingControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59ECF87A1CB7061D00E68F25 /* PostSharingControllerTests.swift */; }; 59FBD5621B5684F300734466 /* ThemeServiceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 59FBD5611B5684F300734466 /* ThemeServiceTests.m */; }; @@ -2486,7 +2485,6 @@ 57B71D4D230DB5F200789A68 /* BlogBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlogBuilder.swift; sourceTree = ""; }; 5948AD101AB73D19006E8882 /* WPAppAnalyticsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = WPAppAnalyticsTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 5960967E1CF7959300848496 /* PostTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostTests.swift; sourceTree = ""; }; - 5981FE041AB8A89A0009E080 /* WPUserAgentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPUserAgentTests.m; sourceTree = ""; }; 59A9AB391B4C3ECD00A433DC /* LocalCoreDataServiceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalCoreDataServiceTests.m; sourceTree = ""; }; 59B48B611B99E132008EBB84 /* JSONObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONObject.swift; path = TestUtilities/JSONObject.swift; sourceTree = ""; }; 59ECF87A1CB7061D00E68F25 /* PostSharingControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PostSharingControllerTests.swift; path = Posts/PostSharingControllerTests.swift; sourceTree = ""; }; @@ -5589,7 +5587,6 @@ F4394D202A3B6F43003955C6 /* Crash Logging */, 93A379EB19FFBF7900415023 /* KeychainTest.m */, 5948AD101AB73D19006E8882 /* WPAppAnalyticsTests.m */, - 5981FE041AB8A89A0009E080 /* WPUserAgentTests.m */, 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */, 82301B8E1E787420009C9C4E /* AppRatingUtilityTests.swift */, F551E7F623FC9A5C00751212 /* Collection+RotateTests.swift */, @@ -9214,7 +9211,6 @@ 3F1B66A323A2F54B0075F09E /* ReaderReblogActionTests.swift in Sources */, FEE48EFF2A4C9855008A48E0 /* Blog+PublicizeTests.swift in Sources */, 08B6E51C1F037ADD00268F57 /* MediaFileManagerTests.swift in Sources */, - 5981FE051AB8A89A0009E080 /* WPUserAgentTests.m in Sources */, 73178C2C21BEE09300E37C9A /* SiteCreationHeaderDataTests.swift in Sources */, 3F28CEAF2A4ACEBE00B79686 /* PrivacySettingsViewControllerTests.swift in Sources */, 08A2AD7B1CCED8E500E84454 /* PostCategoryServiceTests.m in Sources */, diff --git a/WordPress/WordPressTest/WPUserAgentTests.m b/WordPress/WordPressTest/WPUserAgentTests.m deleted file mode 100644 index f2856a408176..000000000000 --- a/WordPress/WordPressTest/WPUserAgentTests.m +++ /dev/null @@ -1,118 +0,0 @@ -#import - -#import "WPUserAgent.h" -@import WebKit; - -static NSString* const WPUserAgentKeyUserAgent = @"UserAgent"; - -@interface WPUserAgentTests : XCTestCase -@end - -@implementation WPUserAgentTests - -- (NSString *)currentUserAgentFromUserDefaults -{ - return [[NSUserDefaults standardUserDefaults] objectForKey:WPUserAgentKeyUserAgent]; -} - -- (NSString *)currentUserAgentFromWebView -{ - return [WKWebView userAgent]; -} - -- (void)testWordPressUserAgent -{ - NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; - NSString *defaultUserAgent = [WPUserAgent defaultUserAgent]; - NSString *expectedUserAgent = [NSString stringWithFormat:@"%@ wp-iphone/%@", defaultUserAgent, appVersion]; - - XCTAssertEqualObjects([WPUserAgent wordPressUserAgent], expectedUserAgent); -} - -- (NSRegularExpression *)webkitUserAgentRegex -{ - NSError *error = nil; - NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:@"^Mozilla/5\\.0 \\([a-zA-Z]+; CPU [\\sa-zA-Z]+ [_0-9]+ like Mac OS X\\) AppleWebKit/605\\.1\\.15 \\(KHTML, like Gecko\\) Mobile/15E148$" options:0 error:&error]; - XCTAssertNil(error); - return regex; -} - -- (void)testUserAgentFormat -{ - NSRegularExpression *regex = [self webkitUserAgentRegex]; - NSString *userAgent = [WPUserAgent webViewUserAgent]; - XCTAssertEqual([regex numberOfMatchesInString:userAgent options:0 range:NSMakeRange(0, userAgent.length)], 1); -} - -// If this test fails, it may mean `WKWebView` uses a user agent with an unexpected format (see `webkitUserAgentRegex`) -// and we may need to adjust `UserAgent.webkitUserAgent`'s implementation to match `WKWebView`'s user agent. -- (void)testWKWebViewUserAgentFormat -{ - NSRegularExpression *regex = [self webkitUserAgentRegex]; - // Please note: WKWebView's user agent may be different on different test device types. - NSString *userAgent = [self currentUserAgentFromWebView]; - XCTAssertEqual([regex numberOfMatchesInString:userAgent options:0 range:NSMakeRange(0, userAgent.length)], 1); -} - -- (void)testUseWordPressUserAgentInWebViews -{ - NSString *defaultUA = [WPUserAgent defaultUserAgent]; - NSString *wordPressUA = [WPUserAgent wordPressUserAgent]; - - [[NSUserDefaults standardUserDefaults] removeObjectForKey:WPUserAgentKeyUserAgent]; - [[NSUserDefaults standardUserDefaults] registerDefaults:@{WPUserAgentKeyUserAgent: defaultUA}]; - - XCTAssertEqualObjects([self currentUserAgentFromUserDefaults], defaultUA); - XCTAssertEqualObjects([self currentUserAgentFromWebView], defaultUA); - - if (@available(iOS 17, *)) { - XCTSkip("In iOS 17, WKWebView no longer reads User Agent from UserDefaults. Skipping while working on an alternative setup."); - } - - [WPUserAgent useWordPressUserAgentInWebViews]; - XCTAssertEqualObjects([self currentUserAgentFromUserDefaults], wordPressUA); - XCTAssertEqualObjects([self currentUserAgentFromWebView], wordPressUA); -} - -- (void)testThatOriginalRemovalOfWPUseKeyUserAgentDoesntWork { - if (@available(iOS 17, *)) { - XCTSkip("In iOS 17, WKWebView no longer reads User Agent from UserDefaults. Skipping while working on an alternative setup."); - } - - // get the original user agent - NSString *originalUserAgentInWebView = [self currentUserAgentFromWebView]; - NSLog(@"OriginalUserAgent (WebView): %@", originalUserAgentInWebView); - - // set a new one - [[NSUserDefaults standardUserDefaults] registerDefaults:@{WPUserAgentKeyUserAgent: @"new user agent"}]; - - NSString *changedUserAgentInWebView = [self currentUserAgentFromWebView]; - NSLog(@"changedUserAgent (WebView): %@", changedUserAgentInWebView); - - // try to remove it using old method - [[NSUserDefaults standardUserDefaults] registerDefaults:@{}]; - [[NSUserDefaults standardUserDefaults] removeObjectForKey:WPUserAgentKeyUserAgent]; - - NSString *shouldBeOriginalInWebView = [self currentUserAgentFromWebView]; - NSLog(@"shouldBeOriginal (WebView): %@", shouldBeOriginalInWebView); - - XCTAssertNotEqualObjects(originalUserAgentInWebView, shouldBeOriginalInWebView); -} - -- (void)testThatCallingFromAnotherThreadWorks { - // get the original user agent - dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - XCTAssertNoThrow([WPUserAgent wordPressUserAgent], @"Being called from out of main thread should work"); - }); -} - -- (void)testThatRegistarDefaultJustAdds { - NSDictionary * registrationDomain = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSRegistrationDomain]; - [[NSUserDefaults standardUserDefaults] registerDefaults:@{WPUserAgentKeyUserAgent: @(0)}]; - NSDictionary * changedRegistrationDomain = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSRegistrationDomain]; - - XCTAssertTrue((registrationDomain.count == changedRegistrationDomain.count) || ((registrationDomain.count +1) == changedRegistrationDomain.count), "It should add or reset"); -} - - -@end diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/WordPress/WordPressTest/WPUserAgentTests.swift index 7d8ff063ea91..c497217c634b 100644 --- a/WordPress/WordPressTest/WPUserAgentTests.swift +++ b/WordPress/WordPressTest/WPUserAgentTests.swift @@ -7,7 +7,7 @@ class WPWPUserAgentTests { @Test func userAgentFormat() throws { - let userAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: .standard) + let userAgent = WPUserAgent.defaultUserAgent(userDefaults: .standard) #expect( try webKitUserAgentRegExp().numberOfMatches( @@ -22,10 +22,10 @@ class WPWPUserAgentTests { func wordPressUserAgentValue() throws { let userDefaults = UserDefaults.standard let appVersion = try #require(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) - let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: userDefaults) + let defaultUserAgent = WPUserAgent.defaultUserAgent(userDefaults: userDefaults) let expectedUserAgent = String.init(format: "%@ wp-iphone/%@", defaultUserAgent, appVersion) - #expect(TemporaryWPUserAgent.wordPressUserAgent(userDefaults: userDefaults) == expectedUserAgent) + #expect(WPUserAgent.wordPressUserAgent(userDefaults: userDefaults) == expectedUserAgent) } @Test @MainActor @@ -36,16 +36,16 @@ class WPWPUserAgentTests { } let userDefaults = UserDefaults.standard - let defaultUserAgent = TemporaryWPUserAgent.defaultUserAgent(userDefaults: userDefaults) - let wordPressUserAgent = TemporaryWPUserAgent.wordPressUserAgent(userDefaults: userDefaults) + let defaultUserAgent = WPUserAgent.defaultUserAgent(userDefaults: userDefaults) + let wordPressUserAgent = WPUserAgent.wordPressUserAgent(userDefaults: userDefaults) // FIXME: Is this necessary? // See original implementation at // https://github.com/wordpress-mobile/WordPress-iOS/blob/a6eaa7aa8acb50828449df2d3fccaa50d7def821/WordPress/WordPressTest/WPUserAgentTests.m#L57-L75 - userDefaults.removeObject(forKey: TemporaryWPUserAgent.userAgentKey) - userDefaults.register(defaults: [TemporaryWPUserAgent.userAgentKey: defaultUserAgent]) + userDefaults.removeObject(forKey: WPUserAgent.userAgentKey) + userDefaults.register(defaults: [WPUserAgent.userAgentKey: defaultUserAgent]) - TemporaryWPUserAgent.useWordPressUserAgentInWebViews(userDefaults: userDefaults) + WPUserAgent.useWordPressInWebViews(userDefaults: userDefaults) #expect(try currentUserAgent(userDefaults: userDefaults) == wordPressUserAgent) #expect(try currentUserAgentFromWebView() == wordPressUserAgent) @@ -58,13 +58,13 @@ class WPWPUserAgentTests { func accessingWordPressUserAgentOutsideMainThread() { #expect(throws: Never.self, "Accessing outside the main thread should work") { DispatchQueue.global(qos: .background).sync { - TemporaryWPUserAgent.wordPressUserAgent(userDefaults: .standard) + WPUserAgent.wordPressUserAgent(userDefaults: .standard) } } } func currentUserAgent(userDefaults: UserDefaults) throws -> String { - try #require(userDefaults.object(forKey: TemporaryWPUserAgent.userAgentKey) as? String) + try #require(userDefaults.object(forKey: WPUserAgent.userAgentKey) as? String) } @MainActor From 8bfb22a923034f976404361908e7a0b159d0f43a Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 16:16:41 +1100 Subject: [PATCH 07/10] Add CocoaLumberjack as a dependency to WordPressShared --- Modules/Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/Package.swift b/Modules/Package.swift index 7850155872c8..44084ff8a0cf 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -87,6 +87,7 @@ let package = Package( .target( name: "WordPressShared", dependencies: [ + .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"), .target(name: "SFHFKeychainUtils"), .target(name: "WordPressSharedObjC"), ], From 93d597cca11f231427774668b5f7e1821b702527 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 14 Mar 2025 16:18:12 +1100 Subject: [PATCH 08/10] Move `WPUserAgent` to WordPressShared --- .../WordPressShared/WKWebView+UserAgent.swift | 25 +++++++++++++++++++ .../WordPressShared}/WPUserAgent.swift | 2 +- .../WPUserAgentTests.swift | 2 +- .../Login/WordPressDotComAuthenticator.swift | 1 + WordPress/Classes/Models/Blog/Blog.m | 1 + .../Models/ReaderListTopic+Creation.swift | 1 + .../Classes/Models/WPAccount+RestApi.swift | 2 +- .../WordPressOrgRestApi+WordPress.swift | 1 + .../Services/AuthenticationService.swift | 1 + .../BloggingPromptsService.swift | 1 + .../Page Layouts/PageLayoutService.swift | 1 + .../Services/PostServiceRemoteFactory.swift | 2 +- .../Services/PushAuthenticationService.swift | 1 + .../Classes/Services/ReaderCardService.swift | 1 + .../Services/ReaderSiteSearchService.swift | 1 + ...ReaderTopicService+FollowedInterests.swift | 1 + .../ReaderTopicService+FollowedSites.swift | 1 + .../ReaderTopicService+Interests.swift | 1 + .../ReaderTopicService+SiteInfo.swift | 1 + .../ReaderTopicService+Subscriptions.swift | 1 + .../Classes/Services/SiteAddressService.swift | 1 + .../Services/SiteAssemblyService.swift | 1 + .../Services/SiteSegmentsService.swift | 2 +- WordPress/Classes/Stores/ActivityStore.swift | 1 + WordPress/Classes/Stores/PluginStore.swift | 1 + .../Classes/Stores/StatsInsightsStore.swift | 1 + .../Classes/Stores/StatsPeriodStore.swift | 1 + .../Classes/Stores/StatsRevampStore.swift | 1 + WordPress/Classes/Stores/TimeZoneStore.swift | 1 + .../AutomatedTransferHelper.swift | 1 + .../WordPressComRestApi+Defaults.swift | 1 + .../Webview/BlazeWebViewController.swift | 1 + .../Navigation/ReaderNavigationPath.swift | 1 + .../Sharing/ShareAppContentPresenter.swift | 2 ++ .../TemplatePreviewViewController.swift | 2 +- .../SiteDesignSectionLoader.swift | 1 + .../Final Assembly/AssembledSiteView.swift | 2 +- .../Subscribers/StatsSubscribersStore.swift | 1 + .../RootViewCoordinator+WhatIsNew.swift | 1 + WordPress/WordPress.xcodeproj/project.pbxproj | 4 --- 40 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 Modules/Sources/WordPressShared/WKWebView+UserAgent.swift rename {WordPress/Classes/Utility => Modules/Sources/WordPressShared}/WPUserAgent.swift (99%) rename {WordPress/WordPressTest => Modules/Tests/WordPressSharedTests}/WPUserAgentTests.swift (99%) diff --git a/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift b/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift new file mode 100644 index 000000000000..0ec89cf91f68 --- /dev/null +++ b/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift @@ -0,0 +1,25 @@ +import CocoaLumberjackSwift +import WebKit + +@objc +public extension WKWebView { + static let userAgentKey = "_userAgent" + + /// Call this method to get the user agent for the WKWebView + @objc + func userAgent() -> String { + guard let userAgent = value(forKey: WKWebView.userAgentKey) as? String, !userAgent.isEmpty else { + // TODO: Original implementation logged a message to Tracks/Sentry + DDLogError("This method for retrieveing the user agent seems to be no longer working. We need to figure out an alternative.") + return "" + } + + return userAgent + } + + /// Static version of the method that returns the current user agent. + @objc + static func userAgent() -> String { + return WKWebView().userAgent() + } +} diff --git a/WordPress/Classes/Utility/WPUserAgent.swift b/Modules/Sources/WordPressShared/WPUserAgent.swift similarity index 99% rename from WordPress/Classes/Utility/WPUserAgent.swift rename to Modules/Sources/WordPressShared/WPUserAgent.swift index e56b16f90f9c..152528a889ac 100644 --- a/WordPress/Classes/Utility/WPUserAgent.swift +++ b/Modules/Sources/WordPressShared/WPUserAgent.swift @@ -1,6 +1,6 @@ +import CocoaLumberjackSwift import Foundation import WebKit -import WordPressShared @objc public class WPUserAgent: NSObject { diff --git a/WordPress/WordPressTest/WPUserAgentTests.swift b/Modules/Tests/WordPressSharedTests/WPUserAgentTests.swift similarity index 99% rename from WordPress/WordPressTest/WPUserAgentTests.swift rename to Modules/Tests/WordPressSharedTests/WPUserAgentTests.swift index c497217c634b..fa028658b16c 100644 --- a/WordPress/WordPressTest/WPUserAgentTests.swift +++ b/Modules/Tests/WordPressSharedTests/WPUserAgentTests.swift @@ -1,7 +1,7 @@ import Foundation import Testing import WebKit -@testable import WordPress +import WordPressShared class WPWPUserAgentTests { diff --git a/WordPress/Classes/Login/WordPressDotComAuthenticator.swift b/WordPress/Classes/Login/WordPressDotComAuthenticator.swift index 6e3703c81dec..fddead0549f8 100644 --- a/WordPress/Classes/Login/WordPressDotComAuthenticator.swift +++ b/WordPress/Classes/Login/WordPressDotComAuthenticator.swift @@ -3,6 +3,7 @@ import AuthenticationServices import Foundation import UIKit import WordPressData +import WordPressShared /// Log in or sign up a WordPress.com account via web. /// diff --git a/WordPress/Classes/Models/Blog/Blog.m b/WordPress/Classes/Models/Blog/Blog.m index 1884459def73..e41f18171680 100644 --- a/WordPress/Classes/Models/Blog/Blog.m +++ b/WordPress/Classes/Models/Blog/Blog.m @@ -2,6 +2,7 @@ #import "WPAccount.h" #import "AccountService.h" @import WordPressDataObjC; +@import WordPressShared; #import "WordPress-Swift.h" @import SFHFKeychainUtils; diff --git a/WordPress/Classes/Models/ReaderListTopic+Creation.swift b/WordPress/Classes/Models/ReaderListTopic+Creation.swift index 2f0abdfd6e2a..327e1bbcd8aa 100644 --- a/WordPress/Classes/Models/ReaderListTopic+Creation.swift +++ b/WordPress/Classes/Models/ReaderListTopic+Creation.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared extension ReaderListTopic { diff --git a/WordPress/Classes/Models/WPAccount+RestApi.swift b/WordPress/Classes/Models/WPAccount+RestApi.swift index 365c2521b17a..4bc92f082467 100644 --- a/WordPress/Classes/Models/WPAccount+RestApi.swift +++ b/WordPress/Classes/Models/WPAccount+RestApi.swift @@ -1,5 +1,5 @@ - import Foundation +import WordPressShared import WordPressKit extension WPAccount { diff --git a/WordPress/Classes/Networking/WordPressOrgRestApi+WordPress.swift b/WordPress/Classes/Networking/WordPressOrgRestApi+WordPress.swift index ccba1f67df81..9c22c74b2086 100644 --- a/WordPress/Classes/Networking/WordPressOrgRestApi+WordPress.swift +++ b/WordPress/Classes/Networking/WordPressOrgRestApi+WordPress.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared import WordPressKit private func apiBase(blog: Blog) -> URL? { diff --git a/WordPress/Classes/Services/AuthenticationService.swift b/WordPress/Classes/Services/AuthenticationService.swift index e8cb48b0fcec..8638808e4115 100644 --- a/WordPress/Classes/Services/AuthenticationService.swift +++ b/WordPress/Classes/Services/AuthenticationService.swift @@ -1,5 +1,6 @@ import AutomatticTracks import Foundation +import WordPressShared class AuthenticationService { diff --git a/WordPress/Classes/Services/BloggingPrompts/BloggingPromptsService.swift b/WordPress/Classes/Services/BloggingPrompts/BloggingPromptsService.swift index 0f7c7c1ed23e..e30bf1a23a5b 100644 --- a/WordPress/Classes/Services/BloggingPrompts/BloggingPromptsService.swift +++ b/WordPress/Classes/Services/BloggingPrompts/BloggingPromptsService.swift @@ -1,6 +1,7 @@ import CoreData import WordPressData import WordPressKit +import WordPressShared class BloggingPromptsService { let siteID: NSNumber diff --git a/WordPress/Classes/Services/Page Layouts/PageLayoutService.swift b/WordPress/Classes/Services/Page Layouts/PageLayoutService.swift index 937ac59af4c2..b34da9beb67c 100644 --- a/WordPress/Classes/Services/Page Layouts/PageLayoutService.swift +++ b/WordPress/Classes/Services/Page Layouts/PageLayoutService.swift @@ -2,6 +2,7 @@ import UIKit import CoreData import Gutenberg import WordPressKit +import WordPressShared class PageLayoutService { private struct Parameters { diff --git a/WordPress/Classes/Services/PostServiceRemoteFactory.swift b/WordPress/Classes/Services/PostServiceRemoteFactory.swift index 4d43327c3565..4741ba1c7b6d 100644 --- a/WordPress/Classes/Services/PostServiceRemoteFactory.swift +++ b/WordPress/Classes/Services/PostServiceRemoteFactory.swift @@ -1,6 +1,6 @@ - import Foundation import WordPressKit +import WordPressShared @objc class PostServiceRemoteFactory: NSObject { @objc func forBlog(_ blog: Blog) -> PostServiceRemote? { diff --git a/WordPress/Classes/Services/PushAuthenticationService.swift b/WordPress/Classes/Services/PushAuthenticationService.swift index 748977366e8b..dc224dbd27ba 100644 --- a/WordPress/Classes/Services/PushAuthenticationService.swift +++ b/WordPress/Classes/Services/PushAuthenticationService.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared /// The purpose of this service is to encapsulate the Restful API that performs Mobile 2FA /// Code Verification. diff --git a/WordPress/Classes/Services/ReaderCardService.swift b/WordPress/Classes/Services/ReaderCardService.swift index b9a8334fc2d4..5641e3519958 100644 --- a/WordPress/Classes/Services/ReaderCardService.swift +++ b/WordPress/Classes/Services/ReaderCardService.swift @@ -1,5 +1,6 @@ import Foundation import WordPressKit +import WordPressShared protocol ReaderCardServiceRemote { func fetchStreamCards(stream: ReaderStream, diff --git a/WordPress/Classes/Services/ReaderSiteSearchService.swift b/WordPress/Classes/Services/ReaderSiteSearchService.swift index ebc9179c1f8d..ac5d68fa1533 100644 --- a/WordPress/Classes/Services/ReaderSiteSearchService.swift +++ b/WordPress/Classes/Services/ReaderSiteSearchService.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared typealias ReaderSiteSearchSuccessBlock = (_ feeds: [ReaderFeed], _ hasMore: Bool, _ feedCount: Int) -> Void typealias ReaderSiteSearchFailureBlock = (_ error: Error?) -> Void diff --git a/WordPress/Classes/Services/ReaderTopicService+FollowedInterests.swift b/WordPress/Classes/Services/ReaderTopicService+FollowedInterests.swift index 4b0ddcc894aa..2e516d8fcce5 100644 --- a/WordPress/Classes/Services/ReaderTopicService+FollowedInterests.swift +++ b/WordPress/Classes/Services/ReaderTopicService+FollowedInterests.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared // MARK: - ReaderFollowedInterestsService diff --git a/WordPress/Classes/Services/ReaderTopicService+FollowedSites.swift b/WordPress/Classes/Services/ReaderTopicService+FollowedSites.swift index d652d3c963ae..bdf0f6704ce7 100644 --- a/WordPress/Classes/Services/ReaderTopicService+FollowedSites.swift +++ b/WordPress/Classes/Services/ReaderTopicService+FollowedSites.swift @@ -1,3 +1,4 @@ +import WordPressShared extension ReaderTopicService { diff --git a/WordPress/Classes/Services/ReaderTopicService+Interests.swift b/WordPress/Classes/Services/ReaderTopicService+Interests.swift index e7c51b78730c..4a225af12553 100644 --- a/WordPress/Classes/Services/ReaderTopicService+Interests.swift +++ b/WordPress/Classes/Services/ReaderTopicService+Interests.swift @@ -1,5 +1,6 @@ import Foundation import WordPressKit +import WordPressShared // MARK: - ReaderInterestsService diff --git a/WordPress/Classes/Services/ReaderTopicService+SiteInfo.swift b/WordPress/Classes/Services/ReaderTopicService+SiteInfo.swift index a134ac9a4881..d598eb00a08e 100644 --- a/WordPress/Classes/Services/ReaderTopicService+SiteInfo.swift +++ b/WordPress/Classes/Services/ReaderTopicService+SiteInfo.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared /// Protocol representing a service that retrieves the users followed interests/tags protocol ReaderSiteInfoService: AnyObject { diff --git a/WordPress/Classes/Services/ReaderTopicService+Subscriptions.swift b/WordPress/Classes/Services/ReaderTopicService+Subscriptions.swift index cd1fa124fbfe..67287cfdfd1c 100644 --- a/WordPress/Classes/Services/ReaderTopicService+Subscriptions.swift +++ b/WordPress/Classes/Services/ReaderTopicService+Subscriptions.swift @@ -1,5 +1,6 @@ import Foundation import WordPressKit +import WordPressShared private enum SubscriptionAction { case notifications(siteId: Int) diff --git a/WordPress/Classes/Services/SiteAddressService.swift b/WordPress/Classes/Services/SiteAddressService.swift index ef5af1bbe480..0ba3152ca403 100644 --- a/WordPress/Classes/Services/SiteAddressService.swift +++ b/WordPress/Classes/Services/SiteAddressService.swift @@ -1,4 +1,5 @@ import WordPressKit +import WordPressShared // MARK: - SiteAddressService diff --git a/WordPress/Classes/Services/SiteAssemblyService.swift b/WordPress/Classes/Services/SiteAssemblyService.swift index c94f6af44564..325f2c2891aa 100644 --- a/WordPress/Classes/Services/SiteAssemblyService.swift +++ b/WordPress/Classes/Services/SiteAssemblyService.swift @@ -1,5 +1,6 @@ import Foundation import WordPressData +import WordPressShared /// Site Creation Notification /// diff --git a/WordPress/Classes/Services/SiteSegmentsService.swift b/WordPress/Classes/Services/SiteSegmentsService.swift index 010a33cc9a38..e733e70aae58 100644 --- a/WordPress/Classes/Services/SiteSegmentsService.swift +++ b/WordPress/Classes/Services/SiteSegmentsService.swift @@ -1,6 +1,6 @@ - import Foundation import WordPressKit +import WordPressShared /// Abstracts the service to obtain site types typealias SiteSegmentsServiceCompletion = (SiteSegmentsResult) -> Void diff --git a/WordPress/Classes/Stores/ActivityStore.swift b/WordPress/Classes/Stores/ActivityStore.swift index 3a81d6752b08..58fc86e6bb32 100644 --- a/WordPress/Classes/Stores/ActivityStore.swift +++ b/WordPress/Classes/Stores/ActivityStore.swift @@ -1,6 +1,7 @@ import Foundation import WordPressKit import WordPressFlux +import WordPressShared // MARK: - Store helper types diff --git a/WordPress/Classes/Stores/PluginStore.swift b/WordPress/Classes/Stores/PluginStore.swift index 8fcb1e274daf..16e9aca567ff 100644 --- a/WordPress/Classes/Stores/PluginStore.swift +++ b/WordPress/Classes/Stores/PluginStore.swift @@ -1,6 +1,7 @@ import Foundation import WordPressFlux import WordPressKit +import WordPressShared enum PluginAction: Action { case activate(id: String, site: JetpackSiteRef) diff --git a/WordPress/Classes/Stores/StatsInsightsStore.swift b/WordPress/Classes/Stores/StatsInsightsStore.swift index 7c5ac2210d98..5e29fb7baebb 100644 --- a/WordPress/Classes/Stores/StatsInsightsStore.swift +++ b/WordPress/Classes/Stores/StatsInsightsStore.swift @@ -1,6 +1,7 @@ import Foundation import WordPressKit import WordPressFlux +import WordPressShared import WidgetKit import JetpackStatsWidgetsCore diff --git a/WordPress/Classes/Stores/StatsPeriodStore.swift b/WordPress/Classes/Stores/StatsPeriodStore.swift index 683e2bf1aaa1..c22af8ed2bc7 100644 --- a/WordPress/Classes/Stores/StatsPeriodStore.swift +++ b/WordPress/Classes/Stores/StatsPeriodStore.swift @@ -1,5 +1,6 @@ import Foundation import WordPressFlux +import WordPressShared import WidgetKit import JetpackStatsWidgetsCore diff --git a/WordPress/Classes/Stores/StatsRevampStore.swift b/WordPress/Classes/Stores/StatsRevampStore.swift index 947d931749bf..914908e9d4c9 100644 --- a/WordPress/Classes/Stores/StatsRevampStore.swift +++ b/WordPress/Classes/Stores/StatsRevampStore.swift @@ -1,5 +1,6 @@ import Foundation import WordPressFlux +import WordPressShared /// StatsRevampStore is created to support use cases in Stats that can combine /// different periods and endpoints. diff --git a/WordPress/Classes/Stores/TimeZoneStore.swift b/WordPress/Classes/Stores/TimeZoneStore.swift index 7c98d71c1bcf..33008ca4baf8 100644 --- a/WordPress/Classes/Stores/TimeZoneStore.swift +++ b/WordPress/Classes/Stores/TimeZoneStore.swift @@ -1,5 +1,6 @@ import WordPressFlux import WordPressKit +import WordPressShared struct TimeZoneQuery {} diff --git a/WordPress/Classes/Utility/Automated Transfer/AutomatedTransferHelper.swift b/WordPress/Classes/Utility/Automated Transfer/AutomatedTransferHelper.swift index 6749e1c5b776..cf7d209e1eca 100644 --- a/WordPress/Classes/Utility/Automated Transfer/AutomatedTransferHelper.swift +++ b/WordPress/Classes/Utility/Automated Transfer/AutomatedTransferHelper.swift @@ -1,5 +1,6 @@ import Foundation import WordPressFlux +import WordPressShared class AutomatedTransferHelper { diff --git a/WordPress/Classes/Utility/Networking/WordPressComRestApi+Defaults.swift b/WordPress/Classes/Utility/Networking/WordPressComRestApi+Defaults.swift index c00bdf3bc1e8..f7e80b761e3c 100644 --- a/WordPress/Classes/Utility/Networking/WordPressComRestApi+Defaults.swift +++ b/WordPress/Classes/Utility/Networking/WordPressComRestApi+Defaults.swift @@ -1,5 +1,6 @@ import Foundation import WordPressKit +import WordPressShared extension WordPressComRestApi { @objc public static func defaultApi(oAuthToken: String? = nil, diff --git a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeWebViewController.swift b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeWebViewController.swift index 3c70c83f989d..dd96b2d7847a 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeWebViewController.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeWebViewController.swift @@ -1,4 +1,5 @@ import UIKit +import WordPressShared @preconcurrency import WebKit @objc protocol BlazeWebViewControllerDelegate { diff --git a/WordPress/Classes/ViewRelated/Reader/Navigation/ReaderNavigationPath.swift b/WordPress/Classes/ViewRelated/Reader/Navigation/ReaderNavigationPath.swift index 9c476c48b477..d2470546cee0 100644 --- a/WordPress/Classes/ViewRelated/Reader/Navigation/ReaderNavigationPath.swift +++ b/WordPress/Classes/ViewRelated/Reader/Navigation/ReaderNavigationPath.swift @@ -1,4 +1,5 @@ import Foundation +import WordPressShared enum ReaderNavigationPath: Hashable { case recent diff --git a/WordPress/Classes/ViewRelated/Sharing/ShareAppContentPresenter.swift b/WordPress/Classes/ViewRelated/Sharing/ShareAppContentPresenter.swift index 1175b1d2e23f..bd6c2045169f 100644 --- a/WordPress/Classes/ViewRelated/Sharing/ShareAppContentPresenter.swift +++ b/WordPress/Classes/ViewRelated/Sharing/ShareAppContentPresenter.swift @@ -1,3 +1,5 @@ +import WordPressShared + /// Encapsulates the logic required to fetch, prepare, and present the contents for sharing the app to others. /// /// The contents for sharing is first fetched from the API, so the share presentation logic is not synchronously executed. diff --git a/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift b/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift index e0ebe8699837..79e52f750bef 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift @@ -1,5 +1,5 @@ - import Foundation +import WordPressShared protocol TemplatePreviewViewDelegate: AnyObject { typealias PreviewDevice = PreviewDeviceSelectionViewController.PreviewDevice diff --git a/WordPress/Classes/ViewRelated/Site Creation/Design Selection/SiteDesignSectionLoader.swift b/WordPress/Classes/ViewRelated/Site Creation/Design Selection/SiteDesignSectionLoader.swift index 8c6675270de1..92adfbe90af5 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Design Selection/SiteDesignSectionLoader.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Design Selection/SiteDesignSectionLoader.swift @@ -1,5 +1,6 @@ import Foundation import WordPressKit +import WordPressShared struct SiteDesignSectionLoader { typealias Assembler = ((SiteIntentVertical?) -> [SiteDesignSection]) diff --git a/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/AssembledSiteView.swift b/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/AssembledSiteView.swift index 5b166cb2e776..41f49ae02bd6 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/AssembledSiteView.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Final Assembly/AssembledSiteView.swift @@ -1,5 +1,5 @@ - import UIKit +import WordPressShared @preconcurrency import WebKit // MARK: AssembledSiteView diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift index 424d87afe06d..8564e4533496 100644 --- a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift +++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift @@ -1,6 +1,7 @@ import Foundation import Combine import WordPressKit +import WordPressShared protocol StatsSubscribersStoreProtocol { var emailsSummary: CurrentValueSubject, Never> { get } diff --git a/WordPress/Classes/ViewRelated/WhatsNew/Dependency container/RootViewCoordinator+WhatIsNew.swift b/WordPress/Classes/ViewRelated/WhatsNew/Dependency container/RootViewCoordinator+WhatIsNew.swift index 08cf26500b73..4da5ad380097 100644 --- a/WordPress/Classes/ViewRelated/WhatsNew/Dependency container/RootViewCoordinator+WhatIsNew.swift +++ b/WordPress/Classes/ViewRelated/WhatsNew/Dependency container/RootViewCoordinator+WhatIsNew.swift @@ -1,3 +1,4 @@ +import WordPressShared /// dependency container for the What's New / Feature Announcements scene extension RootViewCoordinator { diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 5fa011163628..dcb9d4c570ff 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -331,7 +331,6 @@ 3236F7A124B61B950088E8F3 /* ReaderInterestsDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3236F7A024B61B950088E8F3 /* ReaderInterestsDataSourceTests.swift */; }; 323F8F3023A22C4C000BA49C /* SiteCreationRotatingMessageViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C6CDDA23A1FF0D002556FF /* SiteCreationRotatingMessageViewTests.swift */; }; 374CB16215B93C0800DD0EBC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */; }; - 3F03CD1C2D83BDA20047508B /* WPUserAgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */; }; 3F1B66A323A2F54B0075F09E /* ReaderReblogActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */; }; 3F28CEA52A4ABB8800B79686 /* PrivacySettingsAnalyticsTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F28CEA42A4ABB8800B79686 /* PrivacySettingsAnalyticsTrackerTests.swift */; }; 3F28CEA92A4ACB1000B79686 /* AnalyticsEventTrackingSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F28CEA82A4ACB1000B79686 /* AnalyticsEventTrackingSpy.swift */; }; @@ -2139,7 +2138,6 @@ 3236F7A024B61B950088E8F3 /* ReaderInterestsDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderInterestsDataSourceTests.swift; sourceTree = ""; }; 32C6CDDA23A1FF0D002556FF /* SiteCreationRotatingMessageViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationRotatingMessageViewTests.swift; sourceTree = ""; }; 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; - 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WPUserAgentTests.swift; sourceTree = ""; }; 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderReblogActionTests.swift; sourceTree = ""; }; 3F28CEA42A4ABB8800B79686 /* PrivacySettingsAnalyticsTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsAnalyticsTrackerTests.swift; sourceTree = ""; }; 3F28CEA82A4ACB1000B79686 /* AnalyticsEventTrackingSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventTrackingSpy.swift; sourceTree = ""; }; @@ -5587,7 +5585,6 @@ F4394D202A3B6F43003955C6 /* Crash Logging */, 93A379EB19FFBF7900415023 /* KeychainTest.m */, 5948AD101AB73D19006E8882 /* WPAppAnalyticsTests.m */, - 3F03CD1B2D83BDA20047508B /* WPUserAgentTests.swift */, 82301B8E1E787420009C9C4E /* AppRatingUtilityTests.swift */, F551E7F623FC9A5C00751212 /* Collection+RotateTests.swift */, E180BD4B1FB462FF00D0D781 /* CookieJarTests.swift */, @@ -9326,7 +9323,6 @@ 436D5655212209D600CEAA33 /* RegisterDomainDetailsServiceProxyMock.swift in Sources */, F1450CF92437EEBB00A28BFE /* MediaRequestAuthenticatorTests.swift in Sources */, FE6BB1462932289B001E5F7A /* ContentMigrationCoordinatorTests.swift in Sources */, - 3F03CD1C2D83BDA20047508B /* WPUserAgentTests.swift in Sources */, FEFA6AC62A86824A004EE5E6 /* PostHelperJetpackSocialTests.swift in Sources */, 0C391E642A312DB20040EA91 /* BlazeCampaignViewModelTests.swift in Sources */, D821C817210036D9002ED995 /* ActivityContentFactoryTests.swift in Sources */, From 71f19634ae7a791e59e660b411715e3d44f49ffe Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 19 Mar 2025 11:03:18 +1100 Subject: [PATCH 09/10] Add TODO note regarding CocoaLumberjack usage in WordPressShared --- Modules/Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/Package.swift b/Modules/Package.swift index 44084ff8a0cf..ed4365caf768 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -87,6 +87,7 @@ let package = Package( .target( name: "WordPressShared", dependencies: [ + // TODO: Consider removing CocoaLumberjack from this lower level framework .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"), .target(name: "SFHFKeychainUtils"), .target(name: "WordPressSharedObjC"), From f95be4448315d4d49691a88e0759cbfc1f0a9e3b Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 19 Mar 2025 11:29:51 +1100 Subject: [PATCH 10/10] =?UTF-8?q?Remove=20CocoaLumberjack=20from=20WordPre?= =?UTF-8?q?ssShared=20=E2=80=93=20Runtime=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Modules/Package.swift | 2 -- Modules/Sources/WordPressShared/WKWebView+UserAgent.swift | 3 +-- Modules/Sources/WordPressShared/WPUserAgent.swift | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Modules/Package.swift b/Modules/Package.swift index ed4365caf768..7850155872c8 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -87,8 +87,6 @@ let package = Package( .target( name: "WordPressShared", dependencies: [ - // TODO: Consider removing CocoaLumberjack from this lower level framework - .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"), .target(name: "SFHFKeychainUtils"), .target(name: "WordPressSharedObjC"), ], diff --git a/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift b/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift index 0ec89cf91f68..5a6418dfa54a 100644 --- a/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift +++ b/Modules/Sources/WordPressShared/WKWebView+UserAgent.swift @@ -1,4 +1,3 @@ -import CocoaLumberjackSwift import WebKit @objc @@ -10,7 +9,7 @@ public extension WKWebView { func userAgent() -> String { guard let userAgent = value(forKey: WKWebView.userAgentKey) as? String, !userAgent.isEmpty else { // TODO: Original implementation logged a message to Tracks/Sentry - DDLogError("This method for retrieveing the user agent seems to be no longer working. We need to figure out an alternative.") + print("This method for retrieveing the user agent seems to be no longer working. We need to figure out an alternative.") return "" } diff --git a/Modules/Sources/WordPressShared/WPUserAgent.swift b/Modules/Sources/WordPressShared/WPUserAgent.swift index 152528a889ac..b4fcc6a91615 100644 --- a/Modules/Sources/WordPressShared/WPUserAgent.swift +++ b/Modules/Sources/WordPressShared/WPUserAgent.swift @@ -1,4 +1,3 @@ -import CocoaLumberjackSwift import Foundation import WebKit @@ -52,7 +51,7 @@ public class WPUserAgent: NSObject { userDefaults.register(defaults: [userAgentKey: userAgent]) - DDLogVerbose("User-Agent set to \(userAgent)") + print("User-Agent set to \(userAgent)") } /// Returns a user agent string similar to (but may not exactly match) the one used in `WKWebView`.