From 5061ddc500ae8ee8a9a2853688f0ea6bef3a4a5c Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Mon, 16 Sep 2019 14:43:44 +0200 Subject: [PATCH 01/55] Bump version number --- SRGIdentity.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index e904550..303bbc9 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -902,7 +902,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1028,7 +1028,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1216,7 +1216,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1273,7 +1273,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; From d32d62958aa8035b860b7e4a9aa8f82d360cda79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 17 Sep 2019 17:44:39 +0200 Subject: [PATCH 02/55] Prepare the project to build on all platforms --- Common.xcconfig | 18 +++ Demo/Demo.xcconfig | 7 ++ Demo/Info.plist | 6 +- Framework/Framework.xcconfig | 2 + SRGIdentity.xcodeproj/project.pbxproj | 173 +++++++++++++------------- Tests/Tests.xcconfig | 1 + 6 files changed, 116 insertions(+), 91 deletions(-) create mode 100644 Common.xcconfig create mode 100644 Demo/Demo.xcconfig create mode 100644 Framework/Framework.xcconfig create mode 100644 Tests/Tests.xcconfig diff --git a/Common.xcconfig b/Common.xcconfig new file mode 100644 index 0000000..654f225 --- /dev/null +++ b/Common.xcconfig @@ -0,0 +1,18 @@ +// Configuration to have a single target built for all platforms +// See https://davedelong.com/blog/2018/11/15/building-a-crossplatform-framework/ +SUPPORTED_PLATFORMS = iphoneos iphonesimulator appletvos appletvsimulator +TARGETED_DEVICE_FAMILY = 1,2,3 + +CARTHAGE_PLATFORM[sdk=iphone*] = iOS +CARTHAGE_PLATFORM[sdk=appletv*] = tvOS + +// Setup to enable plaform suffixes to enable sources or resources for a specific platform only +// See https://davedelong.com/blog/2018/07/25/conditional-compilation-in-swift-part-2/ +IOS_FILES = *~ios.* +TVOS_FILES = *~tvos.* + +EXCLUDED_SOURCE_FILE_NAMES = $(IOS_FILES) $(TVOS_FILES) + +INCLUDED_SOURCE_FILE_NAMES = +INCLUDED_SOURCE_FILE_NAMES[sdk=iphone*] = $(IOS_FILES) +INCLUDED_SOURCE_FILE_NAMES[sdk=appletv*] = $(TVOS_FILES) diff --git a/Demo/Demo.xcconfig b/Demo/Demo.xcconfig new file mode 100644 index 0000000..9f4fff3 --- /dev/null +++ b/Demo/Demo.xcconfig @@ -0,0 +1,7 @@ +#include "../Common.xcconfig" + +LAUNCH_SCREEN[sdk=iphone*] = LaunchScreen~ios +LAUNCH_SCREEN[sdk=appletv*] = + +APP_ICONS_SOURCE[sdk=iphone*] = AppIcon +APP_ICONS_SOURCE[sdk=appletv*] = App Icon & Top Shelf Image diff --git a/Demo/Info.plist b/Demo/Info.plist index f6303f7..517d5c5 100644 --- a/Demo/Info.plist +++ b/Demo/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Identity CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -12,8 +14,6 @@ 6.0 CFBundleName $(PRODUCT_NAME) - CFBundleDisplayName - Identity CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +39,7 @@ UILaunchStoryboardName - LaunchScreen + $(LAUNCH_SCREEN) UIRequiredDeviceCapabilities armv7 diff --git a/Framework/Framework.xcconfig b/Framework/Framework.xcconfig new file mode 100644 index 0000000..128e811 --- /dev/null +++ b/Framework/Framework.xcconfig @@ -0,0 +1,2 @@ +#include "../Common.xcconfig" + diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 303bbc9..a69c3b0 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -14,24 +14,10 @@ 080D0BE321356CB600AA519A /* MAKVONotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */; }; 080D0BE52135776000AA519A /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE42135776000AA519A /* Mantle.framework */; }; 080D0BE621359E4800AA519A /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE42135776000AA519A /* Mantle.framework */; }; - 080D0BE721359E4800AA519A /* Mantle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE42135776000AA519A /* Mantle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 080D0BE821359E4800AA519A /* libextobjc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE021356CB500AA519A /* libextobjc.framework */; }; - 080D0BE921359E4800AA519A /* libextobjc.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE021356CB500AA519A /* libextobjc.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 080D0BEA21359E4800AA519A /* MAKVONotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */; }; - 080D0BEB21359E4800AA519A /* MAKVONotificationCenter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 080D0BEC21359E4800AA519A /* UICKeyChainStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BD921356A1200AA519A /* UICKeyChainStore.framework */; }; - 080D0BED21359E4800AA519A /* UICKeyChainStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BD921356A1200AA519A /* UICKeyChainStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 08266646216E2B9D00FD8E84 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 08266628216E2B1700FD8E84 /* main.m */; }; - 08266649216E34E500FD8E84 /* SRGIdentity.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0826664A216E34EB00FD8E84 /* FXReachability.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0826664B216E34FC00FD8E84 /* libextobjc.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 080D0BE021356CB500AA519A /* libextobjc.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0826664C216E34FC00FD8E84 /* MAKVONotificationCenter.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0826664D216E34FC00FD8E84 /* Mantle.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 080D0BE42135776000AA519A /* Mantle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0826664E216E34FC00FD8E84 /* SRGLogger.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0826664F216E34FD00FD8E84 /* SRGNetwork.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08266650216E34FD00FD8E84 /* UICKeyChainStore.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 080D0BD921356A1200AA519A /* UICKeyChainStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08266652216E354000FD8E84 /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08266651216E354000FD8E84 /* OHHTTPStubs.framework */; }; - 08266653216E354A00FD8E84 /* OHHTTPStubs.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 08266651216E354000FD8E84 /* OHHTTPStubs.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 0829FA7C2136853C00FE0A28 /* SRGAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = 0829FA752136853C00FE0A28 /* SRGAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0829FA7D2136853C00FE0A28 /* SRGAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = 0829FA762136853C00FE0A28 /* SRGAccount.m */; }; 0829FA7E2136853C00FE0A28 /* SRGIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 0829FA772136853C00FE0A28 /* SRGIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -40,16 +26,13 @@ 0829FA812136853C00FE0A28 /* NSBundle+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0829FA7B2136853C00FE0A28 /* NSBundle+SRGIdentity.m */; }; 084CD6FF21696C0A00905A38 /* SRGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; }; 084CD70021696C3400905A38 /* SRGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; }; - 084CD70121696C3400905A38 /* SRGLogger.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 086BB713216967220079483E /* SRGIdentityLogger.h */; }; 086FB2CB21368ADE00DE4CF2 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 086FB2CA21368ADE00DE4CF2 /* WebKit.framework */; }; 6F0C98F12121E26A00073AB6 /* SRGIdentity.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6F0C98E62121E1C200073AB6 /* SRGIdentity.bundle */; }; 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F19DA7D221DF6E100085C7D /* Localizable.strings */; }; 6F19DA84221E853200085C7D /* Masonry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F979F1E21F6056F002A2495 /* Masonry.framework */; }; - 6F19DA85221E85D300085C7D /* Masonry.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 6F979F1E21F6056F002A2495 /* Masonry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6F6ED100216BA9D800D7E786 /* FXReachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; }; 6F6ED101216BA9F000D7E786 /* FXReachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; }; - 6F6ED102216BA9F000D7E786 /* FXReachability.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6F75EA3C222523870014B6DF /* IdentityBaseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F75EA3A222523870014B6DF /* IdentityBaseTestCase.m */; }; 6F8A93FB20FDCAA800AA6434 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F020FDCAA800AA6434 /* LaunchScreen.storyboard */; }; 6F8A93FC20FDCAA800AA6434 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F120FDCAA800AA6434 /* Images.xcassets */; }; @@ -60,12 +43,10 @@ 6F8A940320FDD01B00AA6434 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6F8A940420FDD01B00AA6434 /* SRGIdentity.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6F979F1F21F6056F002A2495 /* Masonry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F979F1E21F6056F002A2495 /* Masonry.framework */; }; - 6F979F2021F6056F002A2495 /* Masonry.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F979F1E21F6056F002A2495 /* Masonry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6F979F3221F72A18002A2495 /* UIWindow+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */; }; 6F979F3321F72A18002A2495 /* UIWindow+SRGIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */; }; 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; 6F9FFAAD2167925A00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; - 6F9FFAAE2167925A00F781A0 /* SRGNetwork.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController.storyboard */; }; @@ -116,38 +97,10 @@ dstSubfolderSpec = 10; files = ( 6F8A940420FDD01B00AA6434 /* SRGIdentity.framework in Embed Frameworks */, - 080D0BEB21359E4800AA519A /* MAKVONotificationCenter.framework in Embed Frameworks */, - 080D0BE921359E4800AA519A /* libextobjc.framework in Embed Frameworks */, - 6F6ED102216BA9F000D7E786 /* FXReachability.framework in Embed Frameworks */, - 080D0BED21359E4800AA519A /* UICKeyChainStore.framework in Embed Frameworks */, - 6F979F2021F6056F002A2495 /* Masonry.framework in Embed Frameworks */, - 6F9FFAAE2167925A00F781A0 /* SRGNetwork.framework in Embed Frameworks */, - 080D0BE721359E4800AA519A /* Mantle.framework in Embed Frameworks */, - 084CD70121696C3400905A38 /* SRGLogger.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - 6FB74D7A2101D68F00E2D365 /* Copy Files */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 6F19DA85221E85D300085C7D /* Masonry.framework in Copy Files */, - 08266653216E354A00FD8E84 /* OHHTTPStubs.framework in Copy Files */, - 0826664B216E34FC00FD8E84 /* libextobjc.framework in Copy Files */, - 0826664C216E34FC00FD8E84 /* MAKVONotificationCenter.framework in Copy Files */, - 0826664D216E34FC00FD8E84 /* Mantle.framework in Copy Files */, - 0826664E216E34FC00FD8E84 /* SRGLogger.framework in Copy Files */, - 0826664F216E34FD00FD8E84 /* SRGNetwork.framework in Copy Files */, - 08266650216E34FD00FD8E84 /* UICKeyChainStore.framework in Copy Files */, - 0826664A216E34EB00FD8E84 /* FXReachability.framework in Copy Files */, - 08266649216E34E500FD8E84 /* SRGIdentity.framework in Copy Files */, - ); - name = "Copy Files"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -173,6 +126,10 @@ 086BB713216967220079483E /* SRGIdentityLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRGIdentityLogger.h; sourceTree = ""; }; 086FB2CA21368ADE00DE4CF2 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 086FB33521380D9300DE4CF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6F0402F22331318700DA4D97 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; + 6F0402F3233131A000DA4D97 /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; + 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Demo.xcconfig; sourceTree = ""; }; + 6F0402F5233131C600DA4D97 /* Tests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Tests.xcconfig; path = Tests/Tests.xcconfig; sourceTree = SOURCE_ROOT; }; 6F0C98E62121E1C200073AB6 /* SRGIdentity.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SRGIdentity.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SRGIdentity.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6F0EB53F20FC7FA9009C02CF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -260,7 +217,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 08266652216E354000FD8E84 /* OHHTTPStubs.framework in Frameworks */, 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -300,6 +256,7 @@ 6F0EB52720FC7F58009C02CF = { isa = PBXGroup; children = ( + 6F0402F22331318700DA4D97 /* Common.xcconfig */, 6F0EB53C20FC7FA9009C02CF /* Framework */, 6FB74D722101D5D600E2D365 /* Tests */, 6F8A93EE20FDCAA800AA6434 /* Demo */, @@ -326,6 +283,7 @@ 6F0EB53D20FC7FA9009C02CF /* Sources */, 6FCBFEF6210B571C006BC355 /* Resources */, 6F0EB53F20FC7FA9009C02CF /* Info.plist */, + 6F0402F3233131A000DA4D97 /* Framework.xcconfig */, ); path = Framework; sourceTree = ""; @@ -360,6 +318,7 @@ 6F8A93F220FDCAA800AA6434 /* Sources */, 6F8A93EF20FDCAA800AA6434 /* Resources */, 086FB33521380D9300DE4CF2 /* Info.plist */, + 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */, ); path = Demo; sourceTree = ""; @@ -423,9 +382,10 @@ 6FB74D722101D5D600E2D365 /* Tests */ = { isa = PBXGroup; children = ( - 6FB74D762101D5D600E2D365 /* Info.plist */, 6FB74D732101D5D600E2D365 /* Sources */, 08266626216E2B1700FD8E84 /* TestApp */, + 6FB74D762101D5D600E2D365 /* Info.plist */, + 6F0402F5233131C600DA4D97 /* Tests.xcconfig */, ); path = Tests; sourceTree = SOURCE_ROOT; @@ -545,6 +505,7 @@ 6F8A93D520FDCA0800AA6434 /* Frameworks */, 6F8A93D620FDCA0800AA6434 /* Resources */, 6F8A940720FDD01B00AA6434 /* Embed Frameworks */, + 6F0402F72331338A00DA4D97 /* Copy Frameworks (Carthage) */, ); buildRules = ( ); @@ -563,7 +524,6 @@ 6FB74D632101D4D200E2D365 /* Sources */, 6FB74D642101D4D200E2D365 /* Frameworks */, 6FB74D652101D4D200E2D365 /* Resources */, - 6FB74D7A2101D68F00E2D365 /* Copy Files */, ); buildRules = ( ); @@ -678,6 +638,35 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 6F0402F72331338A00DA4D97 /* Copy Frameworks (Carthage) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/FXReachability.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/libextobjc.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/MAKVONotificationCenter.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/Mantle.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/Masonry.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGLogger.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGNetwork.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/UICKeyChainStore.framework", + ); + name = "Copy Frameworks (Carthage)"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 0826662A216E2B7200FD8E84 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -785,7 +774,6 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; @@ -805,7 +793,6 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = "Debug-static"; }; @@ -824,7 +811,6 @@ ); MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; @@ -843,7 +829,6 @@ ); MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = "Release-static"; }; @@ -905,13 +890,15 @@ MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 9.0; }; name = "Debug-static"; }; 6F0C98DB2121E14000073AB6 /* Debug-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; @@ -920,8 +907,8 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)/Static", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -932,7 +919,6 @@ ); MACH_O_TYPE = staticlib; PRODUCT_BUNDLE_IDENTIFIER = ch.srgssr.SRGIdentity; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; }; @@ -940,8 +926,9 @@ }; 6F0C98DC2121E14000073AB6 /* Debug-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( @@ -954,27 +941,27 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = "Debug-static"; }; 6F0C98DD2121E14000073AB6 /* Debug-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", + "$(FRAMEWORK_SEARCH_PATHS)", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SRGIdentity-testapp.app/SRGIdentity-testapp"; }; name = "Debug-static"; @@ -1030,14 +1017,16 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = "Release-static"; }; 6F0C98DF2121E14600073AB6 /* Release-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; @@ -1046,8 +1035,8 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)/Static", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1058,7 +1047,6 @@ ); MACH_O_TYPE = staticlib; PRODUCT_BUNDLE_IDENTIFIER = ch.srgssr.SRGIdentity; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1066,8 +1054,9 @@ }; 6F0C98E02121E14600073AB6 /* Release-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( @@ -1080,33 +1069,34 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = "Release-static"; }; 6F0C98E12121E14600073AB6 /* Release-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", + "$(FRAMEWORK_SEARCH_PATHS)", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SRGIdentity-testapp.app/SRGIdentity-testapp"; }; name = "Release-static"; }; 6F0C98EA2121E1C200073AB6 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; @@ -1121,6 +1111,7 @@ }; 6F0C98EB2121E1C200073AB6 /* Debug-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; @@ -1135,6 +1126,7 @@ }; 6F0C98EC2121E1C200073AB6 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; @@ -1149,6 +1141,7 @@ }; 6F0C98ED2121E1C200073AB6 /* Release-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; @@ -1219,8 +1212,9 @@ MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; @@ -1275,14 +1269,16 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 6F0EB53A20FC7F58009C02CF /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; @@ -1290,7 +1286,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1300,7 +1296,6 @@ "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = ch.srgssr.SRGIdentity; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1308,6 +1303,7 @@ }; 6F0EB53B20FC7F58009C02CF /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; @@ -1315,7 +1311,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1325,7 +1321,6 @@ "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = ch.srgssr.SRGIdentity; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1333,8 +1328,9 @@ }; 6F8A93EC20FDCA0900AA6434 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( @@ -1347,14 +1343,14 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 6F8A93ED20FDCA0900AA6434 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( @@ -1367,48 +1363,49 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; - PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 6FB74D6F2101D4D200E2D365 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", + "$(FRAMEWORK_SEARCH_PATHS)", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SRGIdentity-testapp.app/SRGIdentity-testapp"; }; name = Debug; }; 6FB74D702101D4D200E2D365 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", + "$(FRAMEWORK_SEARCH_PATHS)", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SRGIdentity-testapp.app/SRGIdentity-testapp"; }; name = Release; diff --git a/Tests/Tests.xcconfig b/Tests/Tests.xcconfig new file mode 100644 index 0000000..1403f74 --- /dev/null +++ b/Tests/Tests.xcconfig @@ -0,0 +1 @@ +#include "../Common.xcconfig" From 8a65a3d0dbb6e598bfa2f625a8f37bb2c42f0eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 17 Sep 2019 18:17:20 +0200 Subject: [PATCH 03/55] Build dependencies for tvOS (if possible) --- Cartfile | 2 +- Cartfile.resolved | 8 ++++---- Makefile | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cartfile b/Cartfile index e409f5a..a50d18c 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,5 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "1.3.2_srg3" github "SRGSSR/Masonry" "v1.1.0_srg1" -github "SRGSSR/srgnetwork-ios" "1.0.3" +github "SRGSSR/srgnetwork-ios" "b79ad2c08be51972870daf68db731c1ac80ffe5a" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index ef2139f..6dabc1f 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,9 +1,9 @@ github "AliSoftware/OHHTTPStubs" "8.0.0" github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "1.3.2_srg3" -github "SRGSSR/MAKVONotificationCenter" "1.0_srg3" +github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" github "SRGSSR/Masonry" "v1.1.0_srg1" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" -github "SRGSSR/libextobjc" "0.6_srg1" -github "SRGSSR/srglogger-ios" "1.1" -github "SRGSSR/srgnetwork-ios" "1.0.3" +github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" +github "SRGSSR/srglogger-ios" "d2734b2ddd692344a42314e0384772c4bd9efcfe" +github "SRGSSR/srgnetwork-ios" "b79ad2c08be51972870daf68db731c1ac80ffe5a" diff --git a/Makefile b/Makefile index 60b61ce..9fd77ea 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ #!/usr/bin/xcrun make -f CARTHAGE_FOLDER=Carthage -CARTHAGE_FLAGS=--platform iOS --cache-builds --new-resolver +CARTHAGE_FLAGS=--platform iOS,tvOS --cache-builds --new-resolver .PHONY: all all: bootstrap From 48f1b7eaf9e537d4147f215efe4ba5fe649852f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 17 Sep 2019 18:44:48 +0200 Subject: [PATCH 04/55] Remove Masonry dependency --- Cartfile | 1 - .../Browser/SRGIdentityWebViewController.m | 26 ++++++++++--------- SRGIdentity.xcodeproj/project.pbxproj | 21 --------------- docs/README.md | 1 - 4 files changed, 14 insertions(+), 35 deletions(-) diff --git a/Cartfile b/Cartfile index a50d18c..0176a59 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,4 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "1.3.2_srg3" -github "SRGSSR/Masonry" "v1.1.0_srg1" github "SRGSSR/srgnetwork-ios" "b79ad2c08be51972870daf68db731c1ac80ffe5a" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Framework/Sources/Browser/SRGIdentityWebViewController.m b/Framework/Sources/Browser/SRGIdentityWebViewController.m index ccd3a2e..18325a9 100644 --- a/Framework/Sources/Browser/SRGIdentityWebViewController.m +++ b/Framework/Sources/Browser/SRGIdentityWebViewController.m @@ -10,7 +10,6 @@ #import "SRGIdentityModalTransition.h" #import -#import #import #import @@ -84,17 +83,20 @@ - (void)viewDidLoad webView.navigationDelegate = self; webView.scrollView.delegate = self; [self.view insertSubview:webView atIndex:0]; - [webView mas_makeConstraints:^(MASConstraintMaker *make) { - if (@available(iOS 11, *)) { - make.top.equalTo(self.view); - make.bottom.equalTo(self.view); - make.left.equalTo(self.view.mas_safeAreaLayoutGuideLeft); - make.right.equalTo(self.view.mas_safeAreaLayoutGuideRight); - } - else { - make.edges.equalTo(self.view); - } - }]; + + if (@available(iOS 11, *)) { + webView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ [webView.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [webView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [webView.leftAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leftAnchor], + [webView.rightAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.rightAnchor] ]]; + } + else { + webView.translatesAutoresizingMaskIntoConstraints = YES; + webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + webView.frame = self.view.bounds; + } + self.webView = webView; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index a69c3b0..9e6e897 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -13,10 +13,6 @@ 080D0BE221356CB600AA519A /* libextobjc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE021356CB500AA519A /* libextobjc.framework */; }; 080D0BE321356CB600AA519A /* MAKVONotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */; }; 080D0BE52135776000AA519A /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE42135776000AA519A /* Mantle.framework */; }; - 080D0BE621359E4800AA519A /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE42135776000AA519A /* Mantle.framework */; }; - 080D0BE821359E4800AA519A /* libextobjc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE021356CB500AA519A /* libextobjc.framework */; }; - 080D0BEA21359E4800AA519A /* MAKVONotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */; }; - 080D0BEC21359E4800AA519A /* UICKeyChainStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080D0BD921356A1200AA519A /* UICKeyChainStore.framework */; }; 08266646216E2B9D00FD8E84 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 08266628216E2B1700FD8E84 /* main.m */; }; 0829FA7C2136853C00FE0A28 /* SRGAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = 0829FA752136853C00FE0A28 /* SRGAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0829FA7D2136853C00FE0A28 /* SRGAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = 0829FA762136853C00FE0A28 /* SRGAccount.m */; }; @@ -25,14 +21,11 @@ 0829FA802136853C00FE0A28 /* NSBundle+SRGIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 0829FA7A2136853C00FE0A28 /* NSBundle+SRGIdentity.h */; }; 0829FA812136853C00FE0A28 /* NSBundle+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0829FA7B2136853C00FE0A28 /* NSBundle+SRGIdentity.m */; }; 084CD6FF21696C0A00905A38 /* SRGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; }; - 084CD70021696C3400905A38 /* SRGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; }; 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 086BB713216967220079483E /* SRGIdentityLogger.h */; }; 086FB2CB21368ADE00DE4CF2 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 086FB2CA21368ADE00DE4CF2 /* WebKit.framework */; }; 6F0C98F12121E26A00073AB6 /* SRGIdentity.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6F0C98E62121E1C200073AB6 /* SRGIdentity.bundle */; }; 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F19DA7D221DF6E100085C7D /* Localizable.strings */; }; - 6F19DA84221E853200085C7D /* Masonry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F979F1E21F6056F002A2495 /* Masonry.framework */; }; 6F6ED100216BA9D800D7E786 /* FXReachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; }; - 6F6ED101216BA9F000D7E786 /* FXReachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; }; 6F75EA3C222523870014B6DF /* IdentityBaseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F75EA3A222523870014B6DF /* IdentityBaseTestCase.m */; }; 6F8A93FB20FDCAA800AA6434 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F020FDCAA800AA6434 /* LaunchScreen.storyboard */; }; 6F8A93FC20FDCAA800AA6434 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F120FDCAA800AA6434 /* Images.xcassets */; }; @@ -42,11 +35,9 @@ 6F8A940220FDCBA600AA6434 /* DemosViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A940120FDCBA600AA6434 /* DemosViewController.storyboard */; }; 6F8A940320FDD01B00AA6434 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6F8A940420FDD01B00AA6434 /* SRGIdentity.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 6F979F1F21F6056F002A2495 /* Masonry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F979F1E21F6056F002A2495 /* Masonry.framework */; }; 6F979F3221F72A18002A2495 /* UIWindow+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */; }; 6F979F3321F72A18002A2495 /* UIWindow+SRGIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */; }; 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; - 6F9FFAAD2167925A00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController.storyboard */; }; @@ -150,7 +141,6 @@ 6F8A93F820FDCAA800AA6434 /* DemosViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemosViewController.h; sourceTree = ""; }; 6F8A93F920FDCAA800AA6434 /* DemosViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemosViewController.m; sourceTree = ""; }; 6F8A940120FDCBA600AA6434 /* DemosViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = DemosViewController.storyboard; sourceTree = ""; }; - 6F979F1E21F6056F002A2495 /* Masonry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Masonry.framework; path = Carthage/Build/iOS/Masonry.framework; sourceTree = ""; }; 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+SRGIdentity.m"; sourceTree = ""; }; 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWindow+SRGIdentity.h"; sourceTree = ""; }; 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SRGNetwork.framework; path = Carthage/Build/iOS/SRGNetwork.framework; sourceTree = ""; }; @@ -185,7 +175,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6F19DA84221E853200085C7D /* Masonry.framework in Frameworks */, 6F6ED100216BA9D800D7E786 /* FXReachability.framework in Frameworks */, 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */, 086FB2CB21368ADE00DE4CF2 /* WebKit.framework in Frameworks */, @@ -202,14 +191,6 @@ buildActionMask = 2147483647; files = ( 6F8A940320FDD01B00AA6434 /* SRGIdentity.framework in Frameworks */, - 080D0BEA21359E4800AA519A /* MAKVONotificationCenter.framework in Frameworks */, - 080D0BE821359E4800AA519A /* libextobjc.framework in Frameworks */, - 6F6ED101216BA9F000D7E786 /* FXReachability.framework in Frameworks */, - 080D0BEC21359E4800AA519A /* UICKeyChainStore.framework in Frameworks */, - 6F979F1F21F6056F002A2495 /* Masonry.framework in Frameworks */, - 6F9FFAAD2167925A00F781A0 /* SRGNetwork.framework in Frameworks */, - 080D0BE621359E4800AA519A /* Mantle.framework in Frameworks */, - 084CD70021696C3400905A38 /* SRGLogger.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -368,7 +349,6 @@ 080D0BE021356CB500AA519A /* libextobjc.framework */, 080D0BE121356CB500AA519A /* MAKVONotificationCenter.framework */, 080D0BE42135776000AA519A /* Mantle.framework */, - 6F979F1E21F6056F002A2495 /* Masonry.framework */, 08266651216E354000FD8E84 /* OHHTTPStubs.framework */, 080D0BEE2135A6DD00AA519A /* SafariServices.framework */, 084CD6FE21696C0A00905A38 /* SRGLogger.framework */, @@ -651,7 +631,6 @@ "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/libextobjc.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/MAKVONotificationCenter.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/Mantle.framework", - "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/Masonry.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGLogger.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGNetwork.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/UICKeyChainStore.framework", diff --git a/docs/README.md b/docs/README.md index 5b9223b..e16391a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -32,7 +32,6 @@ The library requires the following frameworks to be added to any target requirin * `libextobjc`: An utility framework. * `MAKVONotificationCenter`: A safe KVO framework. * `Mantle`: The framework used to parse the data. -* `Masonry`: An autolayout framework. * `SRGIdentity`: The identity library framework. * `SRGLogger`: The framework used for internal logging. * `SRGNetwork`: A networking framework. From 48fc73e2c50d985d0a43342b501b423964dba4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Wed, 18 Sep 2019 07:21:22 +0200 Subject: [PATCH 05/55] Add tvOS-compatible FXReachability dependency --- Cartfile | 2 +- Cartfile.resolved | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cartfile b/Cartfile index 0176a59..bb8e23d 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,4 @@ github "Mantle/Mantle" "2.1.0" -github "SRGSSR/FXReachability" "1.3.2_srg3" +github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/srgnetwork-ios" "b79ad2c08be51972870daf68db731c1ac80ffe5a" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 6dabc1f..517284a 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,8 +1,7 @@ github "AliSoftware/OHHTTPStubs" "8.0.0" github "Mantle/Mantle" "2.1.0" -github "SRGSSR/FXReachability" "1.3.2_srg3" +github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" -github "SRGSSR/Masonry" "v1.1.0_srg1" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" github "SRGSSR/srglogger-ios" "d2734b2ddd692344a42314e0384772c4bd9efcfe" From 8f8b5a3db14aa5fe1ca74ea8c6dd3c779aa46e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Wed, 18 Sep 2019 07:36:04 +0200 Subject: [PATCH 06/55] Fix scroll indicator insets on iOS 11 and below --- Framework/Sources/Browser/SRGIdentityWebViewController.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Framework/Sources/Browser/SRGIdentityWebViewController.m b/Framework/Sources/Browser/SRGIdentityWebViewController.m index 18325a9..9b57d11 100644 --- a/Framework/Sources/Browser/SRGIdentityWebViewController.m +++ b/Framework/Sources/Browser/SRGIdentityWebViewController.m @@ -127,7 +127,6 @@ - (void)viewWillLayoutSubviews - (void)updateContentInsets { UIScrollView *scrollView = self.webView.scrollView; - scrollView.scrollIndicatorInsets = UIEdgeInsetsZero; // Must adjust depending on the web page viewport-fit setting, see https://modelessdesign.com/backdrop/283 if (@available(iOS 11, *)) { @@ -137,6 +136,13 @@ - (void)updateContentInsets } } + if (@available(iOS 12, *)) { + scrollView.scrollIndicatorInsets = UIEdgeInsetsZero; + } + else { + scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.f, self.bottomLayoutGuide.length, 0.f); + } + scrollView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.f, self.bottomLayoutGuide.length, 0.f); } From 6ece4cbe1e83c3b997d424ec68f58b999eb1fcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Wed, 18 Sep 2019 09:26:09 +0200 Subject: [PATCH 07/55] Make the framework compile for tvOS --- ...ion.m => SRGIdentityModalTransition~ios.m} | 0 ... => SRGIdentityNavigationController~ios.m} | 0 ...r.m => SRGIdentityWebViewController~ios.m} | 0 ...GIdentityWebViewController~ios.storyboard} | 0 Framework/Sources/SRGIdentityService.m | 33 ++++++++++++++++-- SRGIdentity.xcodeproj/project.pbxproj | 34 +++++++++---------- .../xcschemes/SRGIdentity.xcscheme | 28 +++++++-------- 7 files changed, 59 insertions(+), 36 deletions(-) rename Framework/Sources/Browser/{SRGIdentityModalTransition.m => SRGIdentityModalTransition~ios.m} (100%) rename Framework/Sources/Browser/{SRGIdentityNavigationController.m => SRGIdentityNavigationController~ios.m} (100%) rename Framework/Sources/Browser/{SRGIdentityWebViewController.m => SRGIdentityWebViewController~ios.m} (100%) rename Framework/Sources/Browser/{SRGIdentityWebViewController.storyboard => SRGIdentityWebViewController~ios.storyboard} (100%) diff --git a/Framework/Sources/Browser/SRGIdentityModalTransition.m b/Framework/Sources/Browser/SRGIdentityModalTransition~ios.m similarity index 100% rename from Framework/Sources/Browser/SRGIdentityModalTransition.m rename to Framework/Sources/Browser/SRGIdentityModalTransition~ios.m diff --git a/Framework/Sources/Browser/SRGIdentityNavigationController.m b/Framework/Sources/Browser/SRGIdentityNavigationController~ios.m similarity index 100% rename from Framework/Sources/Browser/SRGIdentityNavigationController.m rename to Framework/Sources/Browser/SRGIdentityNavigationController~ios.m diff --git a/Framework/Sources/Browser/SRGIdentityWebViewController.m b/Framework/Sources/Browser/SRGIdentityWebViewController~ios.m similarity index 100% rename from Framework/Sources/Browser/SRGIdentityWebViewController.m rename to Framework/Sources/Browser/SRGIdentityWebViewController~ios.m diff --git a/Framework/Sources/Browser/SRGIdentityWebViewController.storyboard b/Framework/Sources/Browser/SRGIdentityWebViewController~ios.storyboard similarity index 100% rename from Framework/Sources/Browser/SRGIdentityWebViewController.storyboard rename to Framework/Sources/Browser/SRGIdentityWebViewController~ios.storyboard diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index f133f15..a8cf3fa 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -9,18 +9,24 @@ #import "NSBundle+SRGIdentity.h" #import "SRGIdentityLogger.h" #import "SRGIdentityNavigationController.h" -#import "SRGIdentityWebViewController.h" #import "UIWindow+SRGIdentity.h" +#if TARGET_OS_IOS +#import "SRGIdentityWebViewController.h" +#endif + #import #import #import #import -#import #import #import #import +#if TARGET_OS_IOS +#import +#endif + static SRGIdentityService *s_currentIdentityService; static BOOL s_loggingIn; @@ -63,7 +69,10 @@ - (BOOL)srg_default_application:(UIApplication *)application openURL:(NSURL *)ur @end -@interface SRGIdentityService () +@interface SRGIdentityService () +#if TARGET_OS_IOS + +#endif @property (nonatomic, copy) NSString *identifier; @@ -294,6 +303,7 @@ - (NSString *)queryItemValueFromURL:(NSURL *)URL withName:(NSString *)queryName - (BOOL)loginWithEmailAddress:(NSString *)emailAddress { +#if TARGET_OS_IOS if (s_loggingIn || self.loggedIn) { return NO; } @@ -365,10 +375,15 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress s_loggingIn = YES; return YES; +#else + NSAssert(NO, @"TODO: Implement or make it unavailable for tvOS (and add tvOS method if needed)"); + return YES; +#endif } - (BOOL)logout { +#if TARGET_OS_IOS if (s_loggingIn) { return NO; } @@ -399,6 +414,10 @@ - (BOOL)logout }] requestWithOptions:SRGRequestOptionBackgroundCompletionEnabled] resume]; return YES; +#else + NSAssert(NO, @"TODO: Implement or make it unavailable for tvOS (and add tvOS method if needed)"); + return YES; +#endif } - (void)cleanup @@ -465,6 +484,7 @@ - (void)updateAccount - (void)showAccountView { +#if TARGET_OS_IOS NSAssert(NSThread.isMainThread, @"Must be called from the main thread"); NSURLRequest *request = [self accountPresentationRequest]; @@ -490,6 +510,9 @@ - (void)showAccountView [topViewController presentViewController:accountNavigationController animated:YES completion:nil]; self.accountNavigationController = accountNavigationController; +#else + NSAssert(NO, @"TODO: Implement or make it unavailable for tvOS (and add tvOS method if needed)"); +#endif } - (void)dismissAccountView @@ -600,6 +623,8 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL return NO; } +#if TARGET_OS_IOS + #pragma mark SFSafariViewControllerDelegate delegate - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller @@ -611,6 +636,8 @@ - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller userInfo:nil]; } +#endif + #pragma mark Actions - (void)dismissAccountView:(id)sender diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 9e6e897..a61724d 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -40,13 +40,13 @@ 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; - 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController.storyboard */; }; + 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController~ios.storyboard */; }; 6FCBBD5A221DB644003CE752 /* SRGIdentityNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */; }; - 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController.m */; }; - 6FF846A3221BED95006FC3FC /* SRGIdentityWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController.m */; }; + 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController~ios.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */; }; + 6FF846A3221BED95006FC3FC /* SRGIdentityWebViewController~ios.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController~ios.m */; }; 6FF846A5221BED95006FC3FC /* SRGIdentityWebViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FF846A2221BED95006FC3FC /* SRGIdentityWebViewController.h */; }; 6FF846A8221BF93F006FC3FC /* SRGIdentityModalTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FF846A6221BF93F006FC3FC /* SRGIdentityModalTransition.h */; }; - 6FF846A9221BF93F006FC3FC /* SRGIdentityModalTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FF846A7221BF93F006FC3FC /* SRGIdentityModalTransition.m */; }; + 6FF846A9221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FF846A7221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -148,12 +148,12 @@ 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdentityServiceTestCase.m; sourceTree = ""; }; 6FB74D762101D5D600E2D365 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRGIdentityNavigationController.h; sourceTree = ""; }; - 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SRGIdentityNavigationController.m; sourceTree = ""; }; - 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRGIdentityWebViewController.m; sourceTree = ""; }; - 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SRGIdentityWebViewController.storyboard; sourceTree = ""; }; + 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityNavigationController~ios.m"; sourceTree = ""; }; + 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController~ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityWebViewController~ios.m"; sourceTree = ""; }; + 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController~ios.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "SRGIdentityWebViewController~ios.storyboard"; sourceTree = ""; }; 6FF846A2221BED95006FC3FC /* SRGIdentityWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRGIdentityWebViewController.h; sourceTree = ""; }; 6FF846A6221BF93F006FC3FC /* SRGIdentityModalTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRGIdentityModalTransition.h; sourceTree = ""; }; - 6FF846A7221BF93F006FC3FC /* SRGIdentityModalTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRGIdentityModalTransition.m; sourceTree = ""; }; + 6FF846A7221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityModalTransition~ios.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -392,12 +392,12 @@ isa = PBXGroup; children = ( 6FF846A6221BF93F006FC3FC /* SRGIdentityModalTransition.h */, - 6FF846A7221BF93F006FC3FC /* SRGIdentityModalTransition.m */, + 6FF846A7221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m */, 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */, - 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController.m */, + 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */, 6FF846A2221BED95006FC3FC /* SRGIdentityWebViewController.h */, - 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController.m */, - 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController.storyboard */, + 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController~ios.m */, + 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController~ios.storyboard */, ); path = Browser; sourceTree = ""; @@ -522,7 +522,7 @@ 6F0EB52820FC7F58009C02CF /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1000; + LastUpgradeCheck = 1100; ORGANIZATIONNAME = "SRG SSR"; TargetAttributes = { 0826662D216E2B7200FD8E84 = { @@ -586,7 +586,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController.storyboard in Resources */, + 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */, 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -666,10 +666,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6FF846A9221BF93F006FC3FC /* SRGIdentityModalTransition.m in Sources */, + 6FF846A9221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m in Sources */, 080D0BD7213566C900AA519A /* SRGIdentityService.m in Sources */, - 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController.m in Sources */, - 6FF846A3221BED95006FC3FC /* SRGIdentityWebViewController.m in Sources */, + 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController~ios.m in Sources */, + 6FF846A3221BED95006FC3FC /* SRGIdentityWebViewController~ios.m in Sources */, 0829FA7F2136853C00FE0A28 /* SRGIdentity.m in Sources */, 6F979F3221F72A18002A2495 /* UIWindow+SRGIdentity.m in Sources */, 0829FA812136853C00FE0A28 /* NSBundle+SRGIdentity.m in Sources */, diff --git a/SRGIdentity.xcodeproj/xcshareddata/xcschemes/SRGIdentity.xcscheme b/SRGIdentity.xcodeproj/xcshareddata/xcschemes/SRGIdentity.xcscheme index 43c903f..f40170f 100644 --- a/SRGIdentity.xcodeproj/xcshareddata/xcschemes/SRGIdentity.xcscheme +++ b/SRGIdentity.xcodeproj/xcshareddata/xcschemes/SRGIdentity.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + + + + - - - - - - - - Date: Wed, 18 Sep 2019 09:49:56 +0200 Subject: [PATCH 08/55] Fix (some) demo issues tvOS demo will be updated later. --- Demo/Sources/Demos/DemosViewController.m | 1 - SRGIdentity.xcodeproj/project.pbxproj | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Demo/Sources/Demos/DemosViewController.m b/Demo/Sources/Demos/DemosViewController.m index f4b407e..9109017 100644 --- a/Demo/Sources/Demos/DemosViewController.m +++ b/Demo/Sources/Demos/DemosViewController.m @@ -7,7 +7,6 @@ #import "DemosViewController.h" #import "AppDelegate.h" -#import "SRGIdentityWebViewController.h" #import diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index a61724d..a273dc0 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -22,7 +22,6 @@ 0829FA812136853C00FE0A28 /* NSBundle+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0829FA7B2136853C00FE0A28 /* NSBundle+SRGIdentity.m */; }; 084CD6FF21696C0A00905A38 /* SRGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; }; 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 086BB713216967220079483E /* SRGIdentityLogger.h */; }; - 086FB2CB21368ADE00DE4CF2 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 086FB2CA21368ADE00DE4CF2 /* WebKit.framework */; }; 6F0C98F12121E26A00073AB6 /* SRGIdentity.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6F0C98E62121E1C200073AB6 /* SRGIdentity.bundle */; }; 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F19DA7D221DF6E100085C7D /* Localizable.strings */; }; 6F6ED100216BA9D800D7E786 /* FXReachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; }; @@ -177,7 +176,6 @@ files = ( 6F6ED100216BA9D800D7E786 /* FXReachability.framework in Frameworks */, 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */, - 086FB2CB21368ADE00DE4CF2 /* WebKit.framework in Frameworks */, 080D0BE52135776000AA519A /* Mantle.framework in Frameworks */, 080D0BE221356CB600AA519A /* libextobjc.framework in Frameworks */, 080D0BE321356CB600AA519A /* MAKVONotificationCenter.framework in Frameworks */, @@ -912,7 +910,7 @@ DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Demo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1040,7 +1038,7 @@ DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Demo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1314,7 +1312,7 @@ DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Demo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1334,7 +1332,7 @@ DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", ); INFOPLIST_FILE = Demo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( From c354b1a6e2ae52b4a88051ffaed969784bccf2f3 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Thu, 19 Sep 2019 18:19:50 +0200 Subject: [PATCH 09/55] Restore tests only for iOS --- SRGIdentity.xcodeproj/project.pbxproj | 4 ++++ Tests/Sources/IdentityServiceTestCase.m | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index a273dc0..a571c90 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -737,6 +737,7 @@ /* Begin XCBuildConfiguration section */ 08266642216E2B7400FD8E84 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -756,6 +757,7 @@ }; 08266643216E2B7400FD8E84 /* Debug-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -775,6 +777,7 @@ }; 08266644216E2B7400FD8E84 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -793,6 +796,7 @@ }; 08266645216E2B7400FD8E84 /* Release-static */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; diff --git a/Tests/Sources/IdentityServiceTestCase.m b/Tests/Sources/IdentityServiceTestCase.m index d3a3c11..4c8e7f2 100644 --- a/Tests/Sources/IdentityServiceTestCase.m +++ b/Tests/Sources/IdentityServiceTestCase.m @@ -9,6 +9,8 @@ #import #import +#if TARGET_OS_IOS + static NSString *TestValidToken = @"0123456789"; @interface SRGIdentityService (Private) @@ -554,3 +556,5 @@ - (void)testReportedUnauthorizationWhenLoggedOut } @end + +#endif From 19c0a151bb7b18ec658bb97bd98c4523c280de1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 20 Sep 2019 16:45:17 +0200 Subject: [PATCH 10/55] Make (automatic) code signing settings minimal and consistent --- SRGIdentity.xcodeproj/project.pbxproj | 36 ++++++--------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index a571c90..43aec7c 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -741,7 +741,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; INFOPLIST_FILE = Tests/TestApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -761,7 +760,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; INFOPLIST_FILE = Tests/TestApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -781,7 +779,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; INFOPLIST_FILE = Tests/TestApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -800,7 +797,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; INFOPLIST_FILE = Tests/TestApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -845,7 +841,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; @@ -882,8 +878,6 @@ baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CLANG_ENABLE_CODE_COVERAGE = NO; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( @@ -910,7 +904,6 @@ baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -930,7 +923,7 @@ baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", @@ -979,7 +972,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1010,8 +1003,6 @@ baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CLANG_ENABLE_CODE_COVERAGE = NO; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( @@ -1038,7 +1029,6 @@ baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1058,7 +1048,7 @@ baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", @@ -1080,7 +1070,6 @@ baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Framework/Resources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-resources"; @@ -1095,7 +1084,6 @@ baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Framework/Resources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-resources"; @@ -1110,7 +1098,6 @@ baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Framework/Resources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-resources"; @@ -1125,7 +1112,6 @@ baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Framework/Resources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-resources"; @@ -1167,7 +1153,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; @@ -1231,7 +1217,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1261,8 +1247,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( @@ -1286,8 +1270,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 6F0402F3233131A000DA4D97 /* Framework.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( @@ -1312,7 +1294,6 @@ baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1332,7 +1313,6 @@ baseConfigurationReference = 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICONS_SOURCE)"; - CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = VMGRRW6SG7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1352,7 +1332,7 @@ baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", @@ -1374,7 +1354,7 @@ baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", From 20540892bcf95a7054c6b887e3532d8d1556db45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 20 Sep 2019 16:47:28 +0200 Subject: [PATCH 11/55] Fix demo code signing early failure --- SRGIdentity.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 43aec7c..fd9c303 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -751,6 +751,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; + SDKROOT = iphoneos; }; name = Debug; }; @@ -770,6 +771,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; + SDKROOT = iphoneos; }; name = "Debug-static"; }; @@ -788,6 +790,7 @@ ); MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; + SDKROOT = iphoneos; }; name = Release; }; @@ -806,6 +809,7 @@ ); MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-testapp"; + SDKROOT = iphoneos; }; name = "Release-static"; }; @@ -915,6 +919,7 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; + SDKROOT = iphoneos; }; name = "Debug-static"; }; @@ -1040,6 +1045,7 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; + SDKROOT = iphoneos; }; name = "Release-static"; }; @@ -1305,6 +1311,7 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; + SDKROOT = iphoneos; }; name = Debug; }; @@ -1324,6 +1331,7 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.SRGIdentity-demo"; + SDKROOT = iphoneos; }; name = Release; }; From e3c37dbc26cf0eccf9062ef688eefad5d2357cca Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Fri, 20 Sep 2019 19:55:38 +0200 Subject: [PATCH 12/55] Add tvOS demo icon and support tvOS dark mode --- Demo/Info.plist | 2 ++ .../Content.imageset/Contents.json | 11 ++++++ .../Back.imagestacklayer/Contents.json | 6 ++++ .../Contents.json | 17 ++++++++++ .../Content.imageset/Contents.json | 11 ++++++ .../Front.imagestacklayer/Contents.json | 6 ++++ .../Content.imageset/Contents.json | 11 ++++++ .../Middle.imagestacklayer/Contents.json | 6 ++++ .../Content.imageset/Contents.json | 18 ++++++++++ .../Content.imageset/back@1x.png | Bin 0 -> 1869 bytes .../Content.imageset/back@2x.png | Bin 0 -> 2666 bytes .../Back.imagestacklayer/Contents.json | 6 ++++ .../App Icon.imagestack/Contents.json | 17 ++++++++++ .../Content.imageset/Contents.json | 18 ++++++++++ .../Content.imageset/front@1x.png | Bin 0 -> 6041 bytes .../Content.imageset/front@2x.png | Bin 0 -> 12248 bytes .../Front.imagestacklayer/Contents.json | 6 ++++ .../Content.imageset/Contents.json | 18 ++++++++++ .../Content.imageset/middle@1x.png | Bin 0 -> 4396 bytes .../Content.imageset/middle@2x.png | Bin 0 -> 8178 bytes .../Middle.imagestacklayer/Contents.json | 6 ++++ .../Contents.json | 32 ++++++++++++++++++ .../Contents.json | 16 +++++++++ .../Top Shelf Image.imageset/Contents.json | 16 +++++++++ 24 files changed, 223 insertions(+) create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@1x.png create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@1x.png create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/middle@1x.png create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/middle@2x.png create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json create mode 100644 Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json diff --git a/Demo/Info.plist b/Demo/Info.plist index 517d5c5..315564e 100644 --- a/Demo/Info.plist +++ b/Demo/Info.plist @@ -57,5 +57,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIUserInterfaceStyle + Automatic diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000..48ecb4f --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,11 @@ +{ + "images" : [ + { + "idiom" : "tv" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json new file mode 100644 index 0000000..d29f024 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000..48ecb4f --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,11 @@ +{ + "images" : [ + { + "idiom" : "tv" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000..48ecb4f --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,11 @@ +{ + "images" : [ + { + "idiom" : "tv" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000..e5ca7e3 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,18 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "back@1x.png", + "scale" : "1x" + }, + { + "idiom" : "tv", + "filename" : "back@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@1x.png b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..7e72d1598d42155ab315e3c319b34194e32c9d8a GIT binary patch literal 1869 zcmeAS@N?(olHy`uVBq!ia0y~yV4MJCf8byOk_+ROmNGCfS!aesltlRYSS9D@>LsS+ zC#C9D^!3Zj%k|2Q_413-^$jg8E%gnI z^o@*kfhu&1EAvVcD|GXUl|e>8%y3C9PApr>V059=!0bR4fPE4k(HNZrr}Tyl0hg3X|@W;tVqp?aLLR~%_{~v!B)w{zyNF* zLN*df*2n}R3o^;dGdD3kH9Rw=BmosnmkyFa(GrweoS#z)@@!~cCeWKkV7tJY zA`o)6N`@vTz;FhI0az{)Q%)Zg3Hs1j07j=iJU)ROc#25P115taV0`ax_t6EWtENn6 z=YZlMcP9l;S7$RrOEWWFBRxX~291fO6Hj|PIf}H~uQj-2uwsELH)r-zTb@N`j&2bO zifI$By5-w3Z9To$&E@uj+yH^CFSoAPzhIl=YXyxigxtyKIr(+Q z&kc&%)=cb~boKRb#o4E`A2!@K6`xyvGcI$9ta{n6q^@;+txk?vx2`jb8Q-fs8@2WP z-|TNoTh=u!4Xg+W+`8w(l7a%=^|SV9-&wXK+56D*Lvp@)8a4T^J__xhIY;Yb|H&v7 z8@_8|iQ%id9*3@3vUSadJu>BHn^#SFpS74By5ah_Gdc}T zpRE}lOig5zY-3H45Sx$~;m|h984ZJxm=0nl<+9w3tX*>#R112#`njxgN@xNAAF6e^ literal 0 HcmV?d00001 diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..10c34847721e1a90bb24b16ae796488fc4e132cf GIT binary patch literal 2666 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV0^&A1QfZHI&Tq>)0FA#98etO?xf)9>TG6c zX=bKtq-V&$pfRy@;%RRuN0D~>wFZ|ARxEJk=FDDd%d^PL(JewjF>S(Cw|qOMt*7_8 zx!him8z8Xt<<=GZ7i@EUt)S7RaBE9u?3HCt%GPmtJ&`;&C%?}4xj`}8nu$G=uD<@Q zIQw+=!-o5&;&aPy#$_&%RWJLM)U~d!)yXmI)^%nv<9n57qqd&^oBeHR%esc8ffXTv zTlaieQc$3~e%2oCJIj_Ndmnm!NX}PJqbC2=N1^>Q=V*QGKN+QB!*@+AF??0mD zkF_}xt->p++g8V@)<5NFvv<9}F5{hZLEfRGrLNuY4?Yzuu~})T8#d+Dk+mmP_RM!I z7KzGVn7Q!E=1+FZ`vq=JSih_BFY}9upU)kQ5A06AW3h0OFECO#3p^r=85qP=L734q zNaX_q14o~yi(^Q|oVV8waxy3g955*TKli*USCfkHmz%c6+zbupDrFfMK1esSG6)z) zFfbU7GDZVoG$oAYg3(+snhQpA!Dud^YA)EwU6#eRmv^4+GhlOt!PC{xWt~$(695Rw BAS?g? literal 0 HcmV?d00001 diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json new file mode 100644 index 0000000..d29f024 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000..1dfd792 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,18 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "front@1x.png", + "scale" : "1x" + }, + { + "idiom" : "tv", + "filename" : "front@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@1x.png b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..37a4cd3f2a59da7d5191801fa0a361499d635713 GIT binary patch literal 6041 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 OP}fYZzQ5x5;Qs&!1!cJa literal 0 HcmV?d00001 diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000..5aeb37b --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,18 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "middle@1x.png", + "scale" : "1x" + }, + { + "idiom" : "tv", + "filename" : "middle@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/middle@1x.png b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/middle@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..3ee0eb765073dd2bd3d875eac15a599a66b837e1 GIT binary patch literal 4396 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 MbM|Me&Ujz{4*)OJXaE2J literal 0 HcmV?d00001 diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json new file mode 100644 index 0000000..db288f3 --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json @@ -0,0 +1,32 @@ +{ + "assets" : [ + { + "size" : "1280x768", + "idiom" : "tv", + "filename" : "App Icon - App Store.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "400x240", + "idiom" : "tv", + "filename" : "App Icon.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "2320x720", + "idiom" : "tv", + "filename" : "Top Shelf Image Wide.imageset", + "role" : "top-shelf-image-wide" + }, + { + "size" : "1920x720", + "idiom" : "tv", + "filename" : "Top Shelf Image.imageset", + "role" : "top-shelf-image" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json new file mode 100644 index 0000000..16a370d --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + }, + { + "idiom" : "tv", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json new file mode 100644 index 0000000..16a370d --- /dev/null +++ b/Demo/Resources/Images.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + }, + { + "idiom" : "tv", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file From 8e4d98365642c2b6a797da82ff8c981ad0b36883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 24 Sep 2019 16:21:46 +0200 Subject: [PATCH 13/55] Update dependencies --- Cartfile | 2 +- Cartfile.resolved | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cartfile b/Cartfile index bb8e23d..26ad61b 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,4 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" -github "SRGSSR/srgnetwork-ios" "b79ad2c08be51972870daf68db731c1ac80ffe5a" +github "SRGSSR/srgnetwork-ios" "a4f32bfa9488e6400ca9fa3e69113545650f1623" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 517284a..407cc8c 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -4,5 +4,5 @@ github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" -github "SRGSSR/srglogger-ios" "d2734b2ddd692344a42314e0384772c4bd9efcfe" -github "SRGSSR/srgnetwork-ios" "b79ad2c08be51972870daf68db731c1ac80ffe5a" +github "SRGSSR/srglogger-ios" "7b08e40d2331cf3384739859ab807c5557f19157" +github "SRGSSR/srgnetwork-ios" "a4f32bfa9488e6400ca9fa3e69113545650f1623" From ed597bac4221b82ed8d73d1be0d5bbd6eacbe9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 15 Oct 2019 19:29:42 +0200 Subject: [PATCH 14/55] Apply usual naming convention --- .../Contents.json | 0 .../Identity_dark.pdf | Bin .../Identity_light.pdf | Bin .../Contents.json | 0 .../SRGSSR.pdf | Bin Demo/Resources/LaunchScreen.storyboard | 12 ++++++------ 6 files changed, 6 insertions(+), 6 deletions(-) rename Demo/Resources/Images.xcassets/{Identity.imageset => logo_identity.imageset}/Contents.json (100%) rename Demo/Resources/Images.xcassets/{Identity.imageset => logo_identity.imageset}/Identity_dark.pdf (100%) rename Demo/Resources/Images.xcassets/{Identity.imageset => logo_identity.imageset}/Identity_light.pdf (100%) rename Demo/Resources/Images.xcassets/{SRGSSR.imageset => logo_srgssr.imageset}/Contents.json (100%) rename Demo/Resources/Images.xcassets/{SRGSSR.imageset => logo_srgssr.imageset}/SRGSSR.pdf (100%) diff --git a/Demo/Resources/Images.xcassets/Identity.imageset/Contents.json b/Demo/Resources/Images.xcassets/logo_identity.imageset/Contents.json similarity index 100% rename from Demo/Resources/Images.xcassets/Identity.imageset/Contents.json rename to Demo/Resources/Images.xcassets/logo_identity.imageset/Contents.json diff --git a/Demo/Resources/Images.xcassets/Identity.imageset/Identity_dark.pdf b/Demo/Resources/Images.xcassets/logo_identity.imageset/Identity_dark.pdf similarity index 100% rename from Demo/Resources/Images.xcassets/Identity.imageset/Identity_dark.pdf rename to Demo/Resources/Images.xcassets/logo_identity.imageset/Identity_dark.pdf diff --git a/Demo/Resources/Images.xcassets/Identity.imageset/Identity_light.pdf b/Demo/Resources/Images.xcassets/logo_identity.imageset/Identity_light.pdf similarity index 100% rename from Demo/Resources/Images.xcassets/Identity.imageset/Identity_light.pdf rename to Demo/Resources/Images.xcassets/logo_identity.imageset/Identity_light.pdf diff --git a/Demo/Resources/Images.xcassets/SRGSSR.imageset/Contents.json b/Demo/Resources/Images.xcassets/logo_srgssr.imageset/Contents.json similarity index 100% rename from Demo/Resources/Images.xcassets/SRGSSR.imageset/Contents.json rename to Demo/Resources/Images.xcassets/logo_srgssr.imageset/Contents.json diff --git a/Demo/Resources/Images.xcassets/SRGSSR.imageset/SRGSSR.pdf b/Demo/Resources/Images.xcassets/logo_srgssr.imageset/SRGSSR.pdf similarity index 100% rename from Demo/Resources/Images.xcassets/SRGSSR.imageset/SRGSSR.pdf rename to Demo/Resources/Images.xcassets/logo_srgssr.imageset/SRGSSR.pdf diff --git a/Demo/Resources/LaunchScreen.storyboard b/Demo/Resources/LaunchScreen.storyboard index 9478e62..6ca2beb 100644 --- a/Demo/Resources/LaunchScreen.storyboard +++ b/Demo/Resources/LaunchScreen.storyboard @@ -1,9 +1,9 @@ - + - + @@ -19,10 +19,10 @@ - + - + @@ -42,7 +42,7 @@ - - + + From 85c77d5a649256e8e248e2496e2d83fccde48ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Mon, 4 Nov 2019 08:41:18 +0100 Subject: [PATCH 15/55] Use copy as property --- Framework/Sources/SRGIdentityService.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index a8cf3fa..a4d2b39 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -114,7 +114,7 @@ @interface SRGIdentityService () } free(classList); - s_originalImplementations = [originalImplementations copy]; + s_originalImplementations = originalImplementations.copy; } @implementation SRGIdentityService @@ -238,7 +238,7 @@ - (void)setAccount:(SRGAccount *)account [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceDidUpdateAccountNotification object:self - userInfo:[userInfo copy]]; + userInfo:userInfo.copy]; } - (NSString *)sessionToken @@ -539,7 +539,7 @@ - (NSURLRequest *)accountPresentationRequest NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URLComponents.URL]; [request setValue:[NSString stringWithFormat:@"sessionToken %@", self.sessionToken] forHTTPHeaderField:@"Authorization"]; - return [request copy]; + return request.copy; } #pragma mark Unauthorization reporting From 4c852e3c2b6045064acf239bd9065000010cc256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Mon, 4 Nov 2019 11:40:55 +0100 Subject: [PATCH 16/55] Use class methods --- Framework/Sources/SRGIdentityService.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index a4d2b39..34d74cf 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -664,7 +664,7 @@ - (void)applicationWillEnterForeground:(NSNotification *)notification - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; keyChainStore = %@>", - [self class], + self.class, self, self.keyChainStore]; } @@ -693,7 +693,7 @@ static BOOL swizzled_application_openURL_options(id self, SEL _cmd, UIApplicatio } // Find a proper match along the class hierarchy. This also ensures correct behavior is the app delegate is dynamically - // subclassed, either with a lie (e.g. KVO, for which [self class] lies about the true class nature) or not. + // subclassed, either with a lie (e.g. KVO, for which self.class lies about the true class nature) or not. Class cls = object_getClass(self); while (cls != Nil) { NSValue *key = [NSValue valueWithNonretainedObject:cls]; From d5466b69e79200085745621274bcedf6b6532db6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sat, 21 Sep 2019 18:57:54 +0200 Subject: [PATCH 17/55] Set a different xcconfig for test app --- SRGIdentity.xcodeproj/project.pbxproj | 10 ++++++---- Tests/TestApp/TestApp.xcconfig | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 Tests/TestApp/TestApp.xcconfig diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index fd9c303..cf76c42 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -116,6 +116,7 @@ 086BB713216967220079483E /* SRGIdentityLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRGIdentityLogger.h; sourceTree = ""; }; 086FB2CA21368ADE00DE4CF2 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 086FB33521380D9300DE4CF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0895B2E023368DF7009922C6 /* TestApp.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TestApp.xcconfig; sourceTree = ""; }; 6F0402F22331318700DA4D97 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; 6F0402F3233131A000DA4D97 /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; 6F0402F4233131AE00DA4D97 /* Demo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Demo.xcconfig; sourceTree = ""; }; @@ -208,6 +209,7 @@ children = ( 08266629216E2B1700FD8E84 /* Info.plist */, 08266628216E2B1700FD8E84 /* main.m */, + 0895B2E023368DF7009922C6 /* TestApp.xcconfig */, ); path = TestApp; sourceTree = ""; @@ -737,7 +739,7 @@ /* Begin XCBuildConfiguration section */ 08266642216E2B7400FD8E84 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; + baseConfigurationReference = 0895B2E023368DF7009922C6 /* TestApp.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -757,7 +759,7 @@ }; 08266643216E2B7400FD8E84 /* Debug-static */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; + baseConfigurationReference = 0895B2E023368DF7009922C6 /* TestApp.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -777,7 +779,7 @@ }; 08266644216E2B7400FD8E84 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; + baseConfigurationReference = 0895B2E023368DF7009922C6 /* TestApp.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -796,7 +798,7 @@ }; 08266645216E2B7400FD8E84 /* Release-static */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6F0402F5233131C600DA4D97 /* Tests.xcconfig */; + baseConfigurationReference = 0895B2E023368DF7009922C6 /* TestApp.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; diff --git a/Tests/TestApp/TestApp.xcconfig b/Tests/TestApp/TestApp.xcconfig new file mode 100644 index 0000000..035e901 --- /dev/null +++ b/Tests/TestApp/TestApp.xcconfig @@ -0,0 +1 @@ +#include "../../Common.xcconfig" From 72ab85d80e38792df0eabfdefcb93769385bf50c Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sun, 10 Nov 2019 20:50:07 +0100 Subject: [PATCH 18/55] Update fastlane for Xcode 11 --- .gitignore | 1 + Cartfile | 2 +- Cartfile.resolved | 4 +- Gemfile | 4 +- Gemfile.lock | 64 ++++++++++++++++------------- fastlane/Fastfile | 99 ++++++++++++++++++++++++++++++++++++++------- fastlane/Pluginfile | 5 ++- 7 files changed, 132 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index b457eba..2ca94d3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ xcuserdata /Carthage +/fastlane/*.xcresult /fastlane/*.xml /vendor diff --git a/Cartfile b/Cartfile index 26ad61b..de16841 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,4 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" -github "SRGSSR/srgnetwork-ios" "a4f32bfa9488e6400ca9fa3e69113545650f1623" +github "SRGSSR/srgnetwork-ios" "295b641dada5c26ef615bf88d7a3f99609175f00" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 407cc8c..fd26eef 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -4,5 +4,5 @@ github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" -github "SRGSSR/srglogger-ios" "7b08e40d2331cf3384739859ab807c5557f19157" -github "SRGSSR/srgnetwork-ios" "a4f32bfa9488e6400ca9fa3e69113545650f1623" +github "SRGSSR/srglogger-ios" "5df2c5599a2664cd23683fdec225567d8d3ec1ba" +github "SRGSSR/srgnetwork-ios" "295b641dada5c26ef615bf88d7a3f99609175f00" diff --git a/Gemfile b/Gemfile index b734015..ea0afbf 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # Autogenerated by fastlane # # Ensure this file is checked in to source control! -source "https://rubygems.org" +source 'https://rubygems.org' gem 'fastlane' diff --git a/Gemfile.lock b/Gemfile.lock index 5586e87..60e9d99 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,12 +1,23 @@ +GIT + remote: https://github.com/SRGSSR/trainer + revision: b39b3a996a18d87b8f19ce3e31a607198ce34581 + tag: 0.9.1.1 + specs: + fastlane-plugin-trainer (0.4.1) + trainer (>= 0.7.0) + trainer (0.9.1.1) + fastlane (>= 2.25.0) + plist (>= 3.1.0, < 4.0.0) + GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.0) - addressable (2.6.0) - public_suffix (>= 2.0.2, < 4.0) + CFPropertyList (3.0.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) atomos (0.1.3) - babosa (1.0.2) - claide (1.0.2) + babosa (1.0.3) + claide (1.0.3) colored (1.2) colored2 (3.1.2) commander-fastlane (4.4.6) @@ -16,18 +27,18 @@ GEM digest-crc (0.4.1) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.4) + dotenv (2.7.5) emoji_regex (1.0.1) - excon (0.65.0) - faraday (0.15.4) + excon (0.68.0) + faraday (0.17.0) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) faraday (>= 0.7.4) http-cookie (~> 1.0.0) faraday_middleware (0.13.1) faraday (>= 0.7.4, < 1.0) - fastimage (2.1.5) - fastlane (2.128.1) + fastimage (2.1.7) + fastlane (2.134.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) @@ -37,9 +48,9 @@ GEM dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 2.0) excon (>= 0.45.0, < 1.0.0) - faraday (~> 0.9) + faraday (~> 0.17) faraday-cookie_jar (~> 0.0.6) - faraday_middleware (~> 0.9) + faraday_middleware (~> 0.13.1) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) google-api-client (>= 0.21.2, < 0.24.0) @@ -52,7 +63,7 @@ GEM multipart-post (~> 2.0.0) plist (>= 3.1.0, < 4.0.0) public_suffix (~> 2.0.0) - rubyzip (>= 1.2.2, < 2.0.0) + rubyzip (>= 1.3.0, < 2.0.0) security (= 0.1.3) simctl (~> 1.6.3) slack-notifier (>= 2.0.0, < 3.0.0) @@ -64,8 +75,7 @@ GEM xcodeproj (>= 1.8.1, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-trainer (0.4.1) - trainer (>= 0.7.0) + fastlane-plugin-xcconfig (2.0.0) gh_inspector (1.1.3) google-api-client (0.23.9) addressable (~> 2.5, >= 2.5.1) @@ -75,9 +85,9 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.0) signet (~> 0.9) - google-cloud-core (1.3.0) + google-cloud-core (1.3.2) google-cloud-env (~> 1.0) - google-cloud-env (1.2.0) + google-cloud-env (1.2.1) faraday (~> 0.11) google-cloud-storage (1.16.0) digest-crc (~> 0.4) @@ -97,12 +107,12 @@ GEM httpclient (2.8.3) json (2.2.0) jwt (2.1.0) - memoist (0.16.0) - mime-types (3.2.2) + memoist (0.16.1) + mime-types (3.3) mime-types-data (~> 3.2015) - mime-types-data (3.2019.0331) + mime-types-data (3.2019.1009) mini_magick (4.9.5) - multi_json (1.13.1) + multi_json (1.14.1) multi_xml (0.6.0) multipart-post (2.0.0) nanaimo (0.2.6) @@ -116,23 +126,20 @@ GEM uber (< 0.2.0) retriable (3.1.2) rouge (2.0.7) - rubyzip (1.2.3) + rubyzip (1.3.0) security (0.1.3) signet (0.11.0) addressable (~> 2.3) faraday (~> 0.9) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.5) + simctl (1.6.6) CFPropertyList naturally slack-notifier (2.3.2) terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - trainer (0.8.2) - fastlane (>= 2.25.0) - plist (>= 3.1.0, < 4.0.0) tty-cursor (0.7.0) tty-screen (0.7.0) tty-spinner (0.9.1) @@ -143,7 +150,7 @@ GEM unf_ext (0.0.7.6) unicode-display_width (1.6.0) word_wrap (1.0.0) - xcodeproj (1.11.0) + xcodeproj (1.13.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -159,7 +166,8 @@ PLATFORMS DEPENDENCIES fastlane - fastlane-plugin-trainer + fastlane-plugin-trainer! + fastlane-plugin-xcconfig BUNDLED WITH 1.16.5 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 6455072..626f870 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Customise this file, documentation can be found here: # https://github.com/fastlane/fastlane/tree/master/fastlane/docs # All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md @@ -7,39 +9,108 @@ # All lines starting with a # are ignored when running `fastlane` # This is the minimum version number required. -fastlane_version "1.95.0" +fastlane_version '2.96.0' default_platform :ios platform :ios do - before_all do |lane| + before_all do ensure_git_status_clean - - Dir.chdir("..") do - sh "make bootstrap" - end + Dir.chdir('..') { sh 'make bootstrap' } end - desc "Run library tests" + desc 'Run library tests' lane :tests do - scan( - output_types: "", - fail_build: false, - clean: true + clean_result_files + + override_test_product_names + + run_tests_with_devices(['iPhone 11']) + + trainer( + path: './fastlane', + output_directory: './fastlane' ) - trainer(output_directory: "./fastlane") end - after_all do |lane| + after_all do reset_git_repo(skip_clean: true) end - error do |lane, exception| + error do clean_build_artifacts reset_git_repo(skip_clean: true, force: true) end end +def clean_result_files + Dir['*.xml'].each { |file| File.delete(file) } + Dir['*.xcresult'].each { |folder| FileUtils.remove_entry(folder, true) } +end + +# Override test product names to split iOS and tvOS test results +def override_test_product_names + set_xcconfig_value( + path: 'Tests/Tests.xcconfig', + name: 'PRODUCT_NAME[sdk=iphone*]', + value: '$(PROJECT_NAME)-iOS' + ) + set_xcconfig_value( + path: 'Tests/Tests.xcconfig', + name: 'PRODUCT_NAME[sdk=appletv*]', + value: '$(PROJECT_NAME)-tvOS' + ) +end + +def run_tests_with_devices(devices) + devices.each do |device| + srg_scan(device) + copy_last_xcresult + end + check_xcresult_count(devices) +end + +def srg_scan(device) + scan( + device: device, + scheme: xcode_project_name, + output_types: '', + output_style: FastlaneCore::Env.truthy?('TRAVIS') ? 'raw' : 'standard', + fail_build: false, + clean: true + ) +end + +def xcresults_path + derived_data_path = lane_context[SharedValues::SCAN_DERIVED_DATA_PATH] + derived_data_path + '/Logs/Test/' +end + +def copy_last_xcresult + file = nil + Dir.chdir(xcresults_path) do + # max == sort.last + file = Dir['*.xcresult'].max + end + file_name = File.basename(file) + FileUtils.copy_entry(xcresults_path + file_name, file_name) +end + +def check_xcresult_count(devices) + return unless Dir['*.xcresult'].count != devices.count + + UI.user_error!('Whoops, unexpected xcresult file count.') +end + +# Return the xcode project name +def xcode_project_name + setting = nil + Dir.chdir('..') do + setting = sh 'xcodebuild -showBuildSettings | grep "PROJECT ="' + end + setting ['PROJECT ='] = '' + setting.gsub(/\s+/, '').chomp +end # More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md # All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile index d829c94..ac2f64b 100644 --- a/fastlane/Pluginfile +++ b/fastlane/Pluginfile @@ -1,5 +1,8 @@ +# frozen_string_literal: true + # Autogenerated by fastlane # # Ensure this file is checked in to source control! -gem 'fastlane-plugin-trainer' +gem 'fastlane-plugin-trainer', git: 'https://github.com/SRGSSR/trainer', tag: '0.9.1.1' +gem 'fastlane-plugin-xcconfig' From 5370c07f395075016a728d51107c86bd1c6b2726 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sun, 10 Nov 2019 21:45:05 +0100 Subject: [PATCH 19/55] Add travis support --- .travis.yml | 11 +++++++++++ docs/README.md | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..048e2d9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: swift +osx_image: xcode11.2 +cache: + bundler: true + directories: + - Carthage +before_install: + - brew update + - brew outdated carthage || brew upgrade carthage +script: + - bundle exec fastlane ios tests diff --git a/docs/README.md b/docs/README.md index e16391a..d4fc8f9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ ![SRG Media Player logo](README-images/logo.png) -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![GitHub releases](https://img.shields.io/github/v/release/SRGSSR/srgidentity-ios)](https://github.com/SRGSSR/srgidentity-ios/releases) [![platform](https://img.shields.io/badge/platfom-ios-blue)](https://github.com/SRGSSR/srgidentity-ios) [![Build Status](https://travis-ci.org/SRGSSR/srgidentity-ios.svg?branch=master)](https://travis-ci.org/SRGSSR/srgidentity-ios/branches) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![GitHub license](https://img.shields.io/github/license/SRGSSR/srgidentity-ios)](https://github.com/SRGSSR/srgidentity-ios/blob/master/LICENSE) ## About From a7d084323bd322e9436e9894825193cdae14bb6f Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Mon, 11 Nov 2019 00:44:04 +0100 Subject: [PATCH 20/55] Fastlane: get library scheme --- fastlane/Fastfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 626f870..52a3db7 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -73,7 +73,7 @@ end def srg_scan(device) scan( device: device, - scheme: xcode_project_name, + scheme: xcode_library_scheme, output_types: '', output_style: FastlaneCore::Env.truthy?('TRAVIS') ? 'raw' : 'standard', fail_build: false, @@ -102,14 +102,14 @@ def check_xcresult_count(devices) UI.user_error!('Whoops, unexpected xcresult file count.') end -# Return the xcode project name -def xcode_project_name - setting = nil +# Returns the library scheme +def xcode_library_scheme + scheme = nil Dir.chdir('..') do - setting = sh 'xcodebuild -showBuildSettings | grep "PROJECT ="' + scheme = sh 'xcodebuild -list | grep "Schemes:" -A 1' end - setting ['PROJECT ='] = '' - setting.gsub(/\s+/, '').chomp + scheme ['Schemes:'] = '' + scheme.gsub(/\s+/, '').chomp end # More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md From 54dc02139917d1083740961a5bd93a69c88e228b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 12 Nov 2019 20:00:56 +0100 Subject: [PATCH 21/55] Avoid assigning a block variable from the result of a method containing a block referencing it --- Tests/Sources/Helpers/IdentityBaseTestCase.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Sources/Helpers/IdentityBaseTestCase.m b/Tests/Sources/Helpers/IdentityBaseTestCase.m index fd9ca56..20d0aa8 100644 --- a/Tests/Sources/Helpers/IdentityBaseTestCase.m +++ b/Tests/Sources/Helpers/IdentityBaseTestCase.m @@ -12,7 +12,9 @@ - (XCTestExpectation *)expectationForSingleNotification:(NSNotificationName)noti { NSString *description = [NSString stringWithFormat:@"Expectation for notification '%@' from object %@", notificationName, objectToObserve]; XCTestExpectation *expectation = [self expectationWithDescription:description]; - __block id observer = [NSNotificationCenter.defaultCenter addObserverForName:notificationName object:objectToObserve queue:nil usingBlock:^(NSNotification * _Nonnull notification) { + + __block id observer = nil; + observer = [NSNotificationCenter.defaultCenter addObserverForName:notificationName object:objectToObserve queue:nil usingBlock:^(NSNotification * _Nonnull notification) { void (^fulfill)(void) = ^{ [expectation fulfill]; [NSNotificationCenter.defaultCenter removeObserver:observer]; From 7da4cedac62d6aa55967c0be30a8e1537387b958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Wed, 13 Nov 2019 06:23:37 +0100 Subject: [PATCH 22/55] Prepare tvOS demo --- ...storyboard => LaunchScreen~ios.storyboard} | 0 Demo/Sources/Demos/DemosViewController.m | 3 +- ...ard => DemosViewController~ios.storyboard} | 29 ++++++------ .../Demos/DemosViewController~tvos.storyboard | 45 +++++++++++++++++++ Demo/Sources/Helpers/Resources.h | 9 ++++ Demo/Sources/Helpers/Resources.m | 17 +++++++ SRGIdentity.xcodeproj/project.pbxproj | 34 ++++++++++---- 7 files changed, 113 insertions(+), 24 deletions(-) rename Demo/Resources/{LaunchScreen.storyboard => LaunchScreen~ios.storyboard} (100%) rename Demo/Sources/Demos/{DemosViewController.storyboard => DemosViewController~ios.storyboard} (77%) create mode 100644 Demo/Sources/Demos/DemosViewController~tvos.storyboard create mode 100644 Demo/Sources/Helpers/Resources.h create mode 100644 Demo/Sources/Helpers/Resources.m diff --git a/Demo/Resources/LaunchScreen.storyboard b/Demo/Resources/LaunchScreen~ios.storyboard similarity index 100% rename from Demo/Resources/LaunchScreen.storyboard rename to Demo/Resources/LaunchScreen~ios.storyboard diff --git a/Demo/Sources/Demos/DemosViewController.m b/Demo/Sources/Demos/DemosViewController.m index 9109017..f8b0b83 100644 --- a/Demo/Sources/Demos/DemosViewController.m +++ b/Demo/Sources/Demos/DemosViewController.m @@ -7,6 +7,7 @@ #import "DemosViewController.h" #import "AppDelegate.h" +#import "Resources.h" #import @@ -25,7 +26,7 @@ @implementation DemosViewController - (instancetype)init { - UIStoryboard *storyboard = [UIStoryboard storyboardWithName:NSStringFromClass(self.class) bundle:nil]; + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:ResourceNameForUIClass(self.class) bundle:nil]; return [storyboard instantiateInitialViewController]; } diff --git a/Demo/Sources/Demos/DemosViewController.storyboard b/Demo/Sources/Demos/DemosViewController~ios.storyboard similarity index 77% rename from Demo/Sources/Demos/DemosViewController.storyboard rename to Demo/Sources/Demos/DemosViewController~ios.storyboard index d0fb97b..617be41 100644 --- a/Demo/Sources/Demos/DemosViewController.storyboard +++ b/Demo/Sources/Demos/DemosViewController~ios.storyboard @@ -1,9 +1,9 @@ - + - + @@ -16,27 +16,26 @@ - + - + - - - - - + + + + diff --git a/Demo/Sources/Demos/DemosViewController~tvos.storyboard b/Demo/Sources/Demos/DemosViewController~tvos.storyboard new file mode 100644 index 0000000..1cb44a9 --- /dev/null +++ b/Demo/Sources/Demos/DemosViewController~tvos.storyboard @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/Sources/Helpers/Resources.h b/Demo/Sources/Helpers/Resources.h new file mode 100644 index 0000000..bb04c38 --- /dev/null +++ b/Demo/Sources/Helpers/Resources.h @@ -0,0 +1,9 @@ +// +// Copyright (c) SRG SSR. All rights reserved. +// +// License information is available from the LICENSE file. +// + +#import + +OBJC_EXPORT NSString *ResourceNameForUIClass(Class cls); diff --git a/Demo/Sources/Helpers/Resources.m b/Demo/Sources/Helpers/Resources.m new file mode 100644 index 0000000..e4b02f6 --- /dev/null +++ b/Demo/Sources/Helpers/Resources.m @@ -0,0 +1,17 @@ +// +// Copyright (c) SRG SSR. All rights reserved. +// +// License information is available from the LICENSE file. +// + +#import "Resources.h" + +NSString *ResourceNameForUIClass(Class cls) +{ + NSString *name = NSStringFromClass(cls); +#if TARGET_OS_TV + return [name stringByAppendingString:@"~tvos"]; +#else + return [name stringByAppendingString:@"~ios"]; +#endif +} diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index cf76c42..b816901 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -24,14 +24,16 @@ 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 086BB713216967220079483E /* SRGIdentityLogger.h */; }; 6F0C98F12121E26A00073AB6 /* SRGIdentity.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6F0C98E62121E1C200073AB6 /* SRGIdentity.bundle */; }; 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F19DA7D221DF6E100085C7D /* Localizable.strings */; }; + 6F55003C237BCB02003476E2 /* DemosViewController~tvos.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F55003B237BCB02003476E2 /* DemosViewController~tvos.storyboard */; }; + 6F550040237BCC04003476E2 /* Resources.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F55003F237BCC04003476E2 /* Resources.m */; }; 6F6ED100216BA9D800D7E786 /* FXReachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */; }; 6F75EA3C222523870014B6DF /* IdentityBaseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F75EA3A222523870014B6DF /* IdentityBaseTestCase.m */; }; - 6F8A93FB20FDCAA800AA6434 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F020FDCAA800AA6434 /* LaunchScreen.storyboard */; }; + 6F8A93FB20FDCAA800AA6434 /* LaunchScreen~ios.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F020FDCAA800AA6434 /* LaunchScreen~ios.storyboard */; }; 6F8A93FC20FDCAA800AA6434 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A93F120FDCAA800AA6434 /* Images.xcassets */; }; 6F8A93FD20FDCAA800AA6434 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F8A93F520FDCAA800AA6434 /* main.m */; }; 6F8A93FE20FDCAA800AA6434 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F8A93F620FDCAA800AA6434 /* AppDelegate.m */; }; 6F8A93FF20FDCAA800AA6434 /* DemosViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F8A93F920FDCAA800AA6434 /* DemosViewController.m */; }; - 6F8A940220FDCBA600AA6434 /* DemosViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A940120FDCBA600AA6434 /* DemosViewController.storyboard */; }; + 6F8A940220FDCBA600AA6434 /* DemosViewController~ios.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F8A940120FDCBA600AA6434 /* DemosViewController~ios.storyboard */; }; 6F8A940320FDD01B00AA6434 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6F8A940420FDD01B00AA6434 /* SRGIdentity.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6F979F3221F72A18002A2495 /* UIWindow+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */; }; @@ -129,18 +131,21 @@ 6F19DA81221DF71300085C7D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 6F19DA82221DF71A00085C7D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 6F19DA83221DF72000085C7D /* rm */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = rm; path = rm.lproj/Localizable.strings; sourceTree = ""; }; + 6F55003B237BCB02003476E2 /* DemosViewController~tvos.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "DemosViewController~tvos.storyboard"; sourceTree = ""; }; + 6F55003E237BCC04003476E2 /* Resources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Resources.h; sourceTree = ""; }; + 6F55003F237BCC04003476E2 /* Resources.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Resources.m; sourceTree = ""; }; 6F6ED0FF216BA9D800D7E786 /* FXReachability.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FXReachability.framework; path = Carthage/Build/iOS/FXReachability.framework; sourceTree = ""; }; 6F75EA3A222523870014B6DF /* IdentityBaseTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdentityBaseTestCase.m; sourceTree = ""; }; 6F75EA3B222523870014B6DF /* IdentityBaseTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdentityBaseTestCase.h; sourceTree = ""; }; 6F8A93D820FDCA0800AA6434 /* SRGIdentity-demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SRGIdentity-demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 6F8A93F020FDCAA800AA6434 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 6F8A93F020FDCAA800AA6434 /* LaunchScreen~ios.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "LaunchScreen~ios.storyboard"; sourceTree = ""; }; 6F8A93F120FDCAA800AA6434 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 6F8A93F420FDCAA800AA6434 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 6F8A93F520FDCAA800AA6434 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 6F8A93F620FDCAA800AA6434 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 6F8A93F820FDCAA800AA6434 /* DemosViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemosViewController.h; sourceTree = ""; }; 6F8A93F920FDCAA800AA6434 /* DemosViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemosViewController.m; sourceTree = ""; }; - 6F8A940120FDCBA600AA6434 /* DemosViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = DemosViewController.storyboard; sourceTree = ""; }; + 6F8A940120FDCBA600AA6434 /* DemosViewController~ios.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "DemosViewController~ios.storyboard"; sourceTree = ""; }; 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+SRGIdentity.m"; sourceTree = ""; }; 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWindow+SRGIdentity.h"; sourceTree = ""; }; 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SRGNetwork.framework; path = Carthage/Build/iOS/SRGNetwork.framework; sourceTree = ""; }; @@ -284,6 +289,15 @@ path = Sources; sourceTree = ""; }; + 6F55003D237BCC04003476E2 /* Helpers */ = { + isa = PBXGroup; + children = ( + 6F55003E237BCC04003476E2 /* Resources.h */, + 6F55003F237BCC04003476E2 /* Resources.m */, + ); + path = Helpers; + sourceTree = ""; + }; 6F75EA39222523870014B6DF /* Helpers */ = { isa = PBXGroup; children = ( @@ -308,7 +322,7 @@ isa = PBXGroup; children = ( 6F8A93F120FDCAA800AA6434 /* Images.xcassets */, - 6F8A93F020FDCAA800AA6434 /* LaunchScreen.storyboard */, + 6F8A93F020FDCAA800AA6434 /* LaunchScreen~ios.storyboard */, ); path = Resources; sourceTree = ""; @@ -318,6 +332,7 @@ children = ( 6F8A93F320FDCAA800AA6434 /* Application */, 6F8A93F720FDCAA800AA6434 /* Demos */, + 6F55003D237BCC04003476E2 /* Helpers */, ); path = Sources; sourceTree = ""; @@ -337,7 +352,8 @@ children = ( 6F8A93F820FDCAA800AA6434 /* DemosViewController.h */, 6F8A93F920FDCAA800AA6434 /* DemosViewController.m */, - 6F8A940120FDCBA600AA6434 /* DemosViewController.storyboard */, + 6F8A940120FDCBA600AA6434 /* DemosViewController~ios.storyboard */, + 6F55003B237BCB02003476E2 /* DemosViewController~tvos.storyboard */, ); path = Demos; sourceTree = ""; @@ -603,8 +619,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6F8A93FB20FDCAA800AA6434 /* LaunchScreen.storyboard in Resources */, - 6F8A940220FDCBA600AA6434 /* DemosViewController.storyboard in Resources */, + 6F8A93FB20FDCAA800AA6434 /* LaunchScreen~ios.storyboard in Resources */, + 6F55003C237BCB02003476E2 /* DemosViewController~tvos.storyboard in Resources */, + 6F8A940220FDCBA600AA6434 /* DemosViewController~ios.storyboard in Resources */, 6F8A93FC20FDCAA800AA6434 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -682,6 +699,7 @@ buildActionMask = 2147483647; files = ( 6F8A93FE20FDCAA800AA6434 /* AppDelegate.m in Sources */, + 6F550040237BCC04003476E2 /* Resources.m in Sources */, 6F8A93FD20FDCAA800AA6434 /* main.m in Sources */, 6F8A93FF20FDCAA800AA6434 /* DemosViewController.m in Sources */, ); From 3e9e9a1464d4e6c9dadcd85bfde631c31017078c Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Thu, 12 Dec 2019 15:35:37 +0100 Subject: [PATCH 23/55] Missing bundle resource name fonction --- .../Sources/Browser/SRGIdentityWebViewController~ios.m | 2 +- Framework/Sources/Categories/NSBundle+SRGIdentity.h | 5 +++++ Framework/Sources/Categories/NSBundle+SRGIdentity.m | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Framework/Sources/Browser/SRGIdentityWebViewController~ios.m b/Framework/Sources/Browser/SRGIdentityWebViewController~ios.m index 9b57d11..cafebf0 100644 --- a/Framework/Sources/Browser/SRGIdentityWebViewController~ios.m +++ b/Framework/Sources/Browser/SRGIdentityWebViewController~ios.m @@ -30,7 +30,7 @@ @implementation SRGIdentityWebViewController - (instancetype)initWithRequest:(NSURLRequest *)request decisionHandler:(WKNavigationActionPolicy (^)(NSURL *URL))decisionHandler { - UIStoryboard *storyboard = [UIStoryboard storyboardWithName:NSStringFromClass(self.class) bundle:NSBundle.srg_identityBundle]; + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:NSBundle.srg_identityBundle]; SRGIdentityWebViewController *webViewController = [storyboard instantiateInitialViewController]; webViewController.request = request; webViewController.decisionHandler = decisionHandler; diff --git a/Framework/Sources/Categories/NSBundle+SRGIdentity.h b/Framework/Sources/Categories/NSBundle+SRGIdentity.h index 5299ed9..982543c 100644 --- a/Framework/Sources/Categories/NSBundle+SRGIdentity.h +++ b/Framework/Sources/Categories/NSBundle+SRGIdentity.h @@ -13,6 +13,11 @@ NS_ASSUME_NONNULL_BEGIN */ #define SRGIdentityLocalizedString(key, comment) [NSBundle.srg_identityBundle localizedStringForKey:(key) value:@"" table:nil] +/** + * Return the recommended resource name for the main resource (xib, storyboard) associated with a class. + */ +OBJC_EXPORT NSString *SRGIdentityResourceNameForUIClass(Class cls); + @interface NSBundle (SRGIdentity) /** diff --git a/Framework/Sources/Categories/NSBundle+SRGIdentity.m b/Framework/Sources/Categories/NSBundle+SRGIdentity.m index a1059ea..edef068 100644 --- a/Framework/Sources/Categories/NSBundle+SRGIdentity.m +++ b/Framework/Sources/Categories/NSBundle+SRGIdentity.m @@ -8,6 +8,16 @@ #import "SRGIdentityService.h" +NSString *SRGIdentityResourceNameForUIClass(Class cls) +{ + NSString *name = NSStringFromClass(cls); +#if TARGET_OS_TV + return [name stringByAppendingString:@"~tvos"]; +#else + return [name stringByAppendingString:@"~ios"]; +#endif +} + @implementation NSBundle (SRGIdentity) #pragma mark Class methods From 5040991dca77387bf1d4b237a5195777d4ee0822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 13:10:58 +0100 Subject: [PATCH 24/55] Prepare login request --- Framework/Sources/SRGIdentityService.m | 40 ++++++++++++++++++-------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index 34d74cf..41323db 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -376,7 +376,23 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress s_loggingIn = YES; return YES; #else - NSAssert(NO, @"TODO: Implement or make it unavailable for tvOS (and add tvOS method if needed)"); + // TODO: Show login view. When the user validates, proceed with this request + NSURL *URL = [self.webserviceURL URLByAppendingPathComponent:@"v1/login"]; + NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL]; + URLRequest.HTTPMethod = @"POST"; + [URLRequest setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; + + NSString *HTTPBodyString = [NSString stringWithFormat:@"login_email=email@test.com&login_password=my_password"]; + NSData *HTTPBody = [HTTPBodyString dataUsingEncoding:NSUTF8StringEncoding]; + [URLRequest setValue:@(HTTPBody.length).stringValue forHTTPHeaderField:@"Content-Length"]; + URLRequest.HTTPBody = HTTPBody; + + [[[SRGRequest dataRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + // TODO: Save token + s_loggingIn = NO; + }] requestWithOptions:SRGRequestOptionCancellationErrorsEnabled] resume]; + + s_loggingIn = YES; return YES; #endif } @@ -403,15 +419,15 @@ - (BOOL)logout userInfo:nil]; NSURL *URL = [self.webserviceURL URLByAppendingPathComponent:@"v1/logout"]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; - request.HTTPMethod = @"DELETE"; - [request setValue:[NSString stringWithFormat:@"sessionToken %@", sessionToken] forHTTPHeaderField:@"Authorization"]; + NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL]; + URLRequest.HTTPMethod = @"DELETE"; + [URLRequest setValue:[NSString stringWithFormat:@"sessionToken %@", sessionToken] forHTTPHeaderField:@"Authorization"]; - [[[SRGRequest dataRequestWithURLRequest:request session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + [[SRGRequest dataRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { SRGIdentityLogInfo(@"service", @"The logout request failed with error %@", error); } - }] requestWithOptions:SRGRequestOptionBackgroundCompletionEnabled] resume]; + }] resume]; return YES; #else @@ -442,10 +458,10 @@ - (void)updateAccount } NSURL *URL = [self.webserviceURL URLByAppendingPathComponent:@"v1/userinfo"]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; - [request setValue:[NSString stringWithFormat:@"sessionToken %@", sessionToken] forHTTPHeaderField:@"Authorization"]; + NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL]; + [URLRequest setValue:[NSString stringWithFormat:@"sessionToken %@", sessionToken] forHTTPHeaderField:@"Authorization"]; - SRGRequest *accountRequest = [SRGRequest objectRequestWithURLRequest:request session:NSURLSession.sharedSession parser:^id _Nullable(NSData * _Nonnull data, NSError * _Nullable __autoreleasing * _Nullable pError) { + SRGRequest *accountRequest = [SRGRequest objectRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession parser:^id _Nullable(NSData * _Nonnull data, NSError * _Nullable __autoreleasing * _Nullable pError) { NSDictionary *JSONDictionary = SRGNetworkJSONDictionaryParser(data, pError); if (! JSONDictionary) { return nil; @@ -487,8 +503,8 @@ - (void)showAccountView #if TARGET_OS_IOS NSAssert(NSThread.isMainThread, @"Must be called from the main thread"); - NSURLRequest *request = [self accountPresentationRequest]; - if (! request) { + NSURLRequest *URLRequest = [self accountPresentationRequest]; + if (! URLRequest) { return; } @@ -496,7 +512,7 @@ - (void)showAccountView return; } - SRGIdentityWebViewController *accountViewController = [[SRGIdentityWebViewController alloc] initWithRequest:request decisionHandler:^WKNavigationActionPolicy(NSURL * _Nonnull URL) { + SRGIdentityWebViewController *accountViewController = [[SRGIdentityWebViewController alloc] initWithRequest:URLRequest decisionHandler:^WKNavigationActionPolicy(NSURL * _Nonnull URL) { return [self handleCallbackURL:URL] ? WKNavigationActionPolicyCancel : WKNavigationActionPolicyAllow; }]; accountViewController.title = SRGIdentityLocalizedString(@"My account", @"Title displayed at the top of the account view"); From 68043f2789682058a63b59af4551ac0075d2c92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 14:06:28 +0100 Subject: [PATCH 25/55] Prepare tvOS login view --- .../Login/SRGIdentityLoginViewController.h | 16 ++++++++++ .../SRGIdentityLoginViewController~tvos.m | 21 +++++++++++++ ...dentityLoginViewController~tvos.storyboard | 30 +++++++++++++++++++ SRGIdentity.xcodeproj/project.pbxproj | 20 +++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 Framework/Sources/Login/SRGIdentityLoginViewController.h create mode 100644 Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m create mode 100644 Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController.h b/Framework/Sources/Login/SRGIdentityLoginViewController.h new file mode 100644 index 0000000..6ef8d5d --- /dev/null +++ b/Framework/Sources/Login/SRGIdentityLoginViewController.h @@ -0,0 +1,16 @@ +// +// Copyright (c) SRG SSR. All rights reserved. +// +// License information is available from the LICENSE file. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +API_AVAILABLE(tvos(9.0)) API_UNAVAILABLE(ios) +@interface SRGIdentityLoginViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m new file mode 100644 index 0000000..c11fe2f --- /dev/null +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -0,0 +1,21 @@ +// +// Copyright (c) SRG SSR. All rights reserved. +// +// License information is available from the LICENSE file. +// + +#import "SRGIdentityLoginViewController.h" + +#import "NSBundle+SRGIdentity.h" + +@implementation SRGIdentityLoginViewController + +#pragma mark Object lifecycle + +- (instancetype)init +{ + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:nil]; + return [storyboard instantiateInitialViewController]; +} + +@end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard new file mode 100644 index 0000000..f11584c --- /dev/null +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index b816901..d34e594 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -38,6 +38,9 @@ 6F8A940420FDD01B00AA6434 /* SRGIdentity.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6F979F3221F72A18002A2495 /* UIWindow+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */; }; 6F979F3321F72A18002A2495 /* UIWindow+SRGIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */; }; + 6F9A1FDC23A27153002ECFC8 /* SRGIdentityLoginViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F9A1FDA23A27153002ECFC8 /* SRGIdentityLoginViewController.h */; }; + 6F9A1FDD23A27153002ECFC8 /* SRGIdentityLoginViewController~tvos.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F9A1FDB23A27153002ECFC8 /* SRGIdentityLoginViewController~tvos.m */; }; + 6F9A1FE023A27199002ECFC8 /* SRGIdentityLoginViewController~tvos.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F9A1FDE23A27193002ECFC8 /* SRGIdentityLoginViewController~tvos.storyboard */; }; 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; @@ -148,6 +151,9 @@ 6F8A940120FDCBA600AA6434 /* DemosViewController~ios.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "DemosViewController~ios.storyboard"; sourceTree = ""; }; 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+SRGIdentity.m"; sourceTree = ""; }; 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWindow+SRGIdentity.h"; sourceTree = ""; }; + 6F9A1FDA23A27153002ECFC8 /* SRGIdentityLoginViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRGIdentityLoginViewController.h; sourceTree = ""; }; + 6F9A1FDB23A27153002ECFC8 /* SRGIdentityLoginViewController~tvos.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityLoginViewController~tvos.m"; sourceTree = ""; }; + 6F9A1FDE23A27193002ECFC8 /* SRGIdentityLoginViewController~tvos.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "SRGIdentityLoginViewController~tvos.storyboard"; sourceTree = ""; }; 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SRGNetwork.framework; path = Carthage/Build/iOS/SRGNetwork.framework; sourceTree = ""; }; 6FB74D672101D4D200E2D365 /* SRGIdentity-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SRGIdentity-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdentityServiceTestCase.m; sourceTree = ""; }; @@ -279,6 +285,7 @@ children = ( 6FF8469F221BED95006FC3FC /* Browser */, 0829FA792136853C00FE0A28 /* Categories */, + 6F9A1FD923A2712E002ECFC8 /* Login */, 0829FA742136853C00FE0A28 /* Model */, 0829FA772136853C00FE0A28 /* SRGIdentity.h */, 0829FA782136853C00FE0A28 /* SRGIdentity.m */, @@ -375,6 +382,16 @@ name = Frameworks; sourceTree = ""; }; + 6F9A1FD923A2712E002ECFC8 /* Login */ = { + isa = PBXGroup; + children = ( + 6F9A1FDA23A27153002ECFC8 /* SRGIdentityLoginViewController.h */, + 6F9A1FDB23A27153002ECFC8 /* SRGIdentityLoginViewController~tvos.m */, + 6F9A1FDE23A27193002ECFC8 /* SRGIdentityLoginViewController~tvos.storyboard */, + ); + path = Login; + sourceTree = ""; + }; 6FB74D722101D5D600E2D365 /* Tests */ = { isa = PBXGroup; children = ( @@ -431,6 +448,7 @@ 0829FA7C2136853C00FE0A28 /* SRGAccount.h in Headers */, 0829FA802136853C00FE0A28 /* NSBundle+SRGIdentity.h in Headers */, 6F979F3321F72A18002A2495 /* UIWindow+SRGIdentity.h in Headers */, + 6F9A1FDC23A27153002ECFC8 /* SRGIdentityLoginViewController.h in Headers */, 0829FA7E2136853C00FE0A28 /* SRGIdentity.h in Headers */, 080D0BD8213566C900AA519A /* SRGIdentityService.h in Headers */, 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */, @@ -603,6 +621,7 @@ buildActionMask = 2147483647; files = ( 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */, + 6F9A1FE023A27199002ECFC8 /* SRGIdentityLoginViewController~tvos.storyboard in Resources */, 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -684,6 +703,7 @@ buildActionMask = 2147483647; files = ( 6FF846A9221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m in Sources */, + 6F9A1FDD23A27153002ECFC8 /* SRGIdentityLoginViewController~tvos.m in Sources */, 080D0BD7213566C900AA519A /* SRGIdentityService.m in Sources */, 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController~ios.m in Sources */, 6FF846A3221BED95006FC3FC /* SRGIdentityWebViewController~ios.m in Sources */, From 94c8f46fb23af5f4ab69c7cf7ac59268720aed04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 14:14:12 +0100 Subject: [PATCH 26/55] Present login view --- .../Login/SRGIdentityLoginViewController.h | 2 ++ .../SRGIdentityLoginViewController~tvos.m | 9 +++-- ...dentityLoginViewController~tvos.storyboard | 33 +++++++++++++++++++ Framework/Sources/SRGIdentityService.m | 24 ++++---------- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController.h b/Framework/Sources/Login/SRGIdentityLoginViewController.h index 6ef8d5d..31916f2 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController.h +++ b/Framework/Sources/Login/SRGIdentityLoginViewController.h @@ -11,6 +11,8 @@ NS_ASSUME_NONNULL_BEGIN API_AVAILABLE(tvos(9.0)) API_UNAVAILABLE(ios) @interface SRGIdentityLoginViewController : UIViewController +- (instancetype)initWithEmailAddress:(nullable NSString *)emailAddress; + @end NS_ASSUME_NONNULL_END diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index c11fe2f..5b1a206 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -12,10 +12,15 @@ @implementation SRGIdentityLoginViewController #pragma mark Object lifecycle -- (instancetype)init +- (instancetype)initWithEmailAddress:(nullable NSString *)emailAddress { - UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:nil]; + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:NSBundle.srg_identityBundle]; return [storyboard instantiateInitialViewController]; } +- (instancetype)init +{ + return [self initWithEmailAddress:nil]; +} + @end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index f11584c..83cd51d 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -19,6 +19,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index 41323db..1a04520 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -11,7 +11,9 @@ #import "SRGIdentityNavigationController.h" #import "UIWindow+SRGIdentity.h" -#if TARGET_OS_IOS +#if TARGET_OS_TV +#import "SRGIdentityLoginViewController.h" +#else #import "SRGIdentityWebViewController.h" #endif @@ -376,23 +378,9 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress s_loggingIn = YES; return YES; #else - // TODO: Show login view. When the user validates, proceed with this request - NSURL *URL = [self.webserviceURL URLByAppendingPathComponent:@"v1/login"]; - NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL]; - URLRequest.HTTPMethod = @"POST"; - [URLRequest setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; - - NSString *HTTPBodyString = [NSString stringWithFormat:@"login_email=email@test.com&login_password=my_password"]; - NSData *HTTPBody = [HTTPBodyString dataUsingEncoding:NSUTF8StringEncoding]; - [URLRequest setValue:@(HTTPBody.length).stringValue forHTTPHeaderField:@"Content-Length"]; - URLRequest.HTTPBody = HTTPBody; - - [[[SRGRequest dataRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - // TODO: Save token - s_loggingIn = NO; - }] requestWithOptions:SRGRequestOptionCancellationErrorsEnabled] resume]; - - s_loggingIn = YES; + SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithEmailAddress:emailAddress]; + UIViewController *topViewController = UIApplication.sharedApplication.keyWindow.srgidentity_topViewController; + [topViewController presentViewController:loginViewController animated:YES completion:nil]; return YES; #endif } From 84e940a7a270627624eb3107b3a35ca0ce594ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 14:42:49 +0100 Subject: [PATCH 27/55] Implement token retrieval --- .../Login/SRGIdentityLoginViewController.h | 4 +- .../SRGIdentityLoginViewController~tvos.m | 120 +++++++++++++++++- ...dentityLoginViewController~tvos.storyboard | 15 ++- Framework/Sources/SRGIdentityService.m | 4 +- 4 files changed, 133 insertions(+), 10 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController.h b/Framework/Sources/Login/SRGIdentityLoginViewController.h index 31916f2..8907045 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController.h +++ b/Framework/Sources/Login/SRGIdentityLoginViewController.h @@ -11,7 +11,9 @@ NS_ASSUME_NONNULL_BEGIN API_AVAILABLE(tvos(9.0)) API_UNAVAILABLE(ios) @interface SRGIdentityLoginViewController : UIViewController -- (instancetype)initWithEmailAddress:(nullable NSString *)emailAddress; +- (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL + websiteURL:(NSURL *)websiteURL + emailAddress:(nullable NSString *)emailAddress; @end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index 5b1a206..a5ebd17 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -8,19 +8,131 @@ #import "NSBundle+SRGIdentity.h" +#import + +@interface SRGIdentityLoginViewController () + +@property (nonatomic, copy) NSString *emailAddress; +@property (nonatomic) NSURL *webserviceURL; +@property (nonatomic) NSURL *websiteURL; + +@property (nonatomic, weak) IBOutlet UITextField *emailAddressTextField; +@property (nonatomic, weak) IBOutlet UITextField *passwordTextField; + +@property (nonatomic, weak) SRGRequest *loginRequest; + +@end + @implementation SRGIdentityLoginViewController #pragma mark Object lifecycle -- (instancetype)initWithEmailAddress:(nullable NSString *)emailAddress +- (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL emailAddress:(NSString *)emailAddress { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:NSBundle.srg_identityBundle]; - return [storyboard instantiateInitialViewController]; + SRGIdentityLoginViewController *viewController = [storyboard instantiateInitialViewController]; + viewController.emailAddress = emailAddress; + viewController.webserviceURL = webserviceURL; + viewController.websiteURL = websiteURL; + return viewController; } -- (instancetype)init +#pragma mark View lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.emailAddressTextField.text = self.emailAddress; + self.emailAddressTextField.placeholder = SRGIdentityLocalizedString(@"Email address", @"Email address text field placeholder"); + + self.passwordTextField.placeholder = SRGIdentityLocalizedString(@"Password", @"Password text field placeholder"); +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + if (self.movingFromParentViewController || self.beingDismissed) { + [self.loginRequest cancel]; + } +} + +#pragma mark Actions + +- (IBAction)login:(id)sender { - return [self initWithEmailAddress:nil]; + NSString *emailAddress = self.emailAddressTextField.text; + if (emailAddress.length == 0) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") + message:SRGIdentityLocalizedString(@"An email address is mandatory", @"Error description when no email address has been provided") + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + return; + } + + NSString *password = self.passwordTextField.text; + if (password.length == 0) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") + message:SRGIdentityLocalizedString(@"An password is mandatory", @"Error description when no password has been provided") + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + return; + } + + NSURL *URL = [self.webserviceURL URLByAppendingPathComponent:@"v1/login"]; + NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL]; + URLRequest.HTTPMethod = @"POST"; + [URLRequest setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; + + NSString *encodedEmailAddress = [emailAddress stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.alphanumericCharacterSet]; + NSString *encodedPassword = [password stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.alphanumericCharacterSet]; + + NSString *HTTPBodyString = [NSString stringWithFormat:@"login_email=%@&login_password=%@", encodedEmailAddress, encodedPassword]; + NSData *HTTPBody = [HTTPBodyString dataUsingEncoding:NSUTF8StringEncoding]; + [URLRequest setValue:@(HTTPBody.length).stringValue forHTTPHeaderField:@"Content-Length"]; + URLRequest.HTTPBody = HTTPBody; + + SRGRequest *loginRequest = [SRGRequest dataRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + void (^showError)(NSError *) = ^(NSError *error) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error", "Title of a generic error alert") + message:error.localizedDescription + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + }; + + if (error) { + showError(error); + return; + } + + NSString *token = nil; + if ([response isKindOfClass:NSHTTPURLResponse.class]) { + NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; + NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:HTTPResponse.allHeaderFields forURL:HTTPResponse.URL]; + for (NSHTTPCookie *cookie in cookies) { + if ([cookie.name isEqualToString:@"identity.provider.sid"]) { + token = cookie.value; + } + } + } + + if (! token) { + // TODO: Proper error + NSError *error = [NSError errorWithDomain:NSURLErrorDomain + code:401 + userInfo:@{ NSLocalizedDescriptionKey : SRGIdentityLocalizedString(@"Wrong email address or password", @"Error message displayed when incorrect user credentials have been supplied") }]; + showError(error); + return; + } + + NSLog(@"Token: %@", token); + }]; + [loginRequest resume]; + self.loginRequest = loginRequest; } @end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index 83cd51d..f66bb49 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -20,13 +20,13 @@ - + - + @@ -34,13 +34,16 @@ - - + + @@ -54,6 +57,10 @@ + + + + diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index 1a04520..b87b4e4 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -378,7 +378,9 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress s_loggingIn = YES; return YES; #else - SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithEmailAddress:emailAddress]; + SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithWebserviceURL:self.webserviceURL + websiteURL:self.websiteURL + emailAddress:emailAddress]; UIViewController *topViewController = UIApplication.sharedApplication.keyWindow.srgidentity_topViewController; [topViewController presentViewController:loginViewController animated:YES completion:nil]; return YES; From 0cc848c8f5fef7f8178352e90a28378d91c38753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 16:16:51 +0100 Subject: [PATCH 28/55] Save returned token --- .../Login/SRGIdentityLoginViewController.h | 3 ++- .../SRGIdentityLoginViewController~tvos.m | 12 ++++++----- Framework/Sources/SRGIdentityService.m | 20 ++++++++++++++----- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController.h b/Framework/Sources/Login/SRGIdentityLoginViewController.h index 8907045..28d125f 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController.h +++ b/Framework/Sources/Login/SRGIdentityLoginViewController.h @@ -13,7 +13,8 @@ API_AVAILABLE(tvos(9.0)) API_UNAVAILABLE(ios) - (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL - emailAddress:(nullable NSString *)emailAddress; + emailAddress:(nullable NSString *)emailAddress + completionBlock:(void (^)(NSString * _Nonnull sessionToken))completionBlock; @end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index a5ebd17..98e2f72 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -15,6 +15,7 @@ @interface SRGIdentityLoginViewController () @property (nonatomic, copy) NSString *emailAddress; @property (nonatomic) NSURL *webserviceURL; @property (nonatomic) NSURL *websiteURL; +@property (nonatomic, copy) void (^completionBlock)(NSString *sessionToken); @property (nonatomic, weak) IBOutlet UITextField *emailAddressTextField; @property (nonatomic, weak) IBOutlet UITextField *passwordTextField; @@ -27,13 +28,14 @@ @implementation SRGIdentityLoginViewController #pragma mark Object lifecycle -- (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL emailAddress:(NSString *)emailAddress +- (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL emailAddress:(nullable NSString *)emailAddress completionBlock:(void (^)(NSString * _Nonnull))completionBlock { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:NSBundle.srg_identityBundle]; SRGIdentityLoginViewController *viewController = [storyboard instantiateInitialViewController]; viewController.emailAddress = emailAddress; viewController.webserviceURL = webserviceURL; viewController.websiteURL = websiteURL; + viewController.completionBlock = completionBlock; return viewController; } @@ -109,18 +111,18 @@ - (IBAction)login:(id)sender return; } - NSString *token = nil; + NSString *sessionToken = nil; if ([response isKindOfClass:NSHTTPURLResponse.class]) { NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:HTTPResponse.allHeaderFields forURL:HTTPResponse.URL]; for (NSHTTPCookie *cookie in cookies) { if ([cookie.name isEqualToString:@"identity.provider.sid"]) { - token = cookie.value; + sessionToken = cookie.value; } } } - if (! token) { + if (! sessionToken) { // TODO: Proper error NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:401 @@ -129,7 +131,7 @@ - (IBAction)login:(id)sender return; } - NSLog(@"Token: %@", token); + self.completionBlock(sessionToken); }]; [loginRequest resume]; self.loginRequest = loginRequest; diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index b87b4e4..20b888f 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -305,8 +305,12 @@ - (NSString *)queryItemValueFromURL:(NSURL *)URL withName:(NSString *)queryName - (BOOL)loginWithEmailAddress:(NSString *)emailAddress { + if (self.loggedIn) { + return NO; + } + #if TARGET_OS_IOS - if (s_loggingIn || self.loggedIn) { + if (s_loggingIn) { return NO; } @@ -378,10 +382,16 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress s_loggingIn = YES; return YES; #else - SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithWebserviceURL:self.webserviceURL - websiteURL:self.websiteURL - emailAddress:emailAddress]; UIViewController *topViewController = UIApplication.sharedApplication.keyWindow.srgidentity_topViewController; + SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithWebserviceURL:self.webserviceURL websiteURL:self.websiteURL emailAddress:emailAddress completionBlock:^(NSString * _Nonnull sessionToken) { + [topViewController dismissViewControllerAnimated:YES completion:nil]; + + self.sessionToken = sessionToken; + [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLoginNotification + object:self + userInfo:nil]; + [self updateAccount]; + }]; [topViewController presentViewController:loginViewController animated:YES completion:nil]; return YES; #endif @@ -604,7 +614,7 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL } NSString *sessionToken = [self queryItemValueFromURL:callbackURL withName:@"token"]; - if (sessionToken) { + if (sessionToken) { self.sessionToken = sessionToken; if (! wasLoggedIn) { From 7878e3ec2f53a375f798de04034b5c4c07a21cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 16:31:30 +0100 Subject: [PATCH 29/55] Complete tvOS implementation --- Demo/Sources/Demos/DemosViewController.m | 4 ++ .../Login/SRGIdentityLoginViewController.h | 3 +- .../SRGIdentityLoginViewController~tvos.m | 16 ++++-- Framework/Sources/SRGIdentityService.h | 2 +- Framework/Sources/SRGIdentityService.m | 57 ++++++++++--------- 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/Demo/Sources/Demos/DemosViewController.m b/Demo/Sources/Demos/DemosViewController.m index f8b0b83..a65ba1c 100644 --- a/Demo/Sources/Demos/DemosViewController.m +++ b/Demo/Sources/Demos/DemosViewController.m @@ -82,11 +82,15 @@ - (void)reloadData #pragma mark Actions +#if TARGET_OS_IOS + - (IBAction)showAccount:(id)sender { [SRGIdentityService.currentIdentityService showAccountView]; } +#endif + - (void)login:(id)sender { NSString *lastEmailAddress = [NSUserDefaults.standardUserDefaults stringForKey:LastLoggedInEmailAddress]; diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController.h b/Framework/Sources/Login/SRGIdentityLoginViewController.h index 28d125f..98eca5f 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController.h +++ b/Framework/Sources/Login/SRGIdentityLoginViewController.h @@ -14,7 +14,8 @@ API_AVAILABLE(tvos(9.0)) API_UNAVAILABLE(ios) - (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL emailAddress:(nullable NSString *)emailAddress - completionBlock:(void (^)(NSString * _Nonnull sessionToken))completionBlock; + tokenBlock:(void (^)(NSString * _Nonnull sessionToken))tokenBlock + dismissalBlock:(void (^)(void))dismissalBlock; @end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index 98e2f72..de9f761 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -15,7 +15,9 @@ @interface SRGIdentityLoginViewController () @property (nonatomic, copy) NSString *emailAddress; @property (nonatomic) NSURL *webserviceURL; @property (nonatomic) NSURL *websiteURL; -@property (nonatomic, copy) void (^completionBlock)(NSString *sessionToken); + +@property (nonatomic, copy) void (^tokenBlock)(NSString *sessionToken); +@property (nonatomic, copy) void (^dismissalBlock)(void); @property (nonatomic, weak) IBOutlet UITextField *emailAddressTextField; @property (nonatomic, weak) IBOutlet UITextField *passwordTextField; @@ -28,14 +30,19 @@ @implementation SRGIdentityLoginViewController #pragma mark Object lifecycle -- (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL emailAddress:(nullable NSString *)emailAddress completionBlock:(void (^)(NSString * _Nonnull))completionBlock +- (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL + websiteURL:(NSURL *)websiteURL + emailAddress:(NSString *)emailAddress + tokenBlock:(void (^)(NSString * _Nonnull))tokenBlock + dismissalBlock:(void (^)(void))dismissalBlock { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:SRGIdentityResourceNameForUIClass(self.class) bundle:NSBundle.srg_identityBundle]; SRGIdentityLoginViewController *viewController = [storyboard instantiateInitialViewController]; viewController.emailAddress = emailAddress; viewController.webserviceURL = webserviceURL; viewController.websiteURL = websiteURL; - viewController.completionBlock = completionBlock; + viewController.tokenBlock = tokenBlock; + viewController.dismissalBlock = dismissalBlock; return viewController; } @@ -57,6 +64,7 @@ - (void)viewDidDisappear:(BOOL)animated if (self.movingFromParentViewController || self.beingDismissed) { [self.loginRequest cancel]; + self.dismissalBlock(); } } @@ -131,7 +139,7 @@ - (IBAction)login:(id)sender return; } - self.completionBlock(sessionToken); + self.tokenBlock(sessionToken); }]; [loginRequest resume]; self.loginRequest = loginRequest; diff --git a/Framework/Sources/SRGIdentityService.h b/Framework/Sources/SRGIdentityService.h index 16d30b7..5e2fc4c 100644 --- a/Framework/Sources/SRGIdentityService.h +++ b/Framework/Sources/SRGIdentityService.h @@ -157,7 +157,7 @@ OBJC_EXPORT NSString * const SRGIdentityServiceDeletedKey; // Key t * @discussion This method must be called from the main thread. If no user is logged in, calling the method does nothing. * Note that only one account view can be presented at any given time. */ -- (void)showAccountView; +- (void)showAccountView API_UNAVAILABLE(tvos); /** * If an unauthorized error is received when using a third-party service on behalf of the current identity, call this diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index 20b888f..e26a408 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -305,15 +305,11 @@ - (NSString *)queryItemValueFromURL:(NSURL *)URL withName:(NSString *)queryName - (BOOL)loginWithEmailAddress:(NSString *)emailAddress { - if (self.loggedIn) { + if (s_loggingIn || self.loggedIn) { return NO; } #if TARGET_OS_IOS - if (s_loggingIn) { - return NO; - } - @weakify(self) void (^completionHandler)(NSURL * _Nullable, NSError * _Nullable) = ^(NSURL * _Nullable callbackURL, NSError * _Nullable error) { void (^notifyCancel)(void) = ^{ @@ -378,12 +374,9 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress else { loginWithSafari(); } - - s_loggingIn = YES; - return YES; #else UIViewController *topViewController = UIApplication.sharedApplication.keyWindow.srgidentity_topViewController; - SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithWebserviceURL:self.webserviceURL websiteURL:self.websiteURL emailAddress:emailAddress completionBlock:^(NSString * _Nonnull sessionToken) { + SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithWebserviceURL:self.webserviceURL websiteURL:self.websiteURL emailAddress:emailAddress tokenBlock:^(NSString * _Nonnull sessionToken) { [topViewController dismissViewControllerAnimated:YES completion:nil]; self.sessionToken = sessionToken; @@ -391,15 +384,18 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress object:self userInfo:nil]; [self updateAccount]; + } dismissalBlock:^{ + s_loggingIn = NO; }]; [topViewController presentViewController:loginViewController animated:YES completion:nil]; - return YES; #endif + + s_loggingIn = YES; + return YES; } - (BOOL)logout { -#if TARGET_OS_IOS if (s_loggingIn) { return NO; } @@ -412,7 +408,10 @@ - (BOOL)logout } [self cleanup]; + +#if TARGET_OS_IOS [self dismissAccountView]; +#endif [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification object:self @@ -430,10 +429,6 @@ - (BOOL)logout }] resume]; return YES; -#else - NSAssert(NO, @"TODO: Implement or make it unavailable for tvOS (and add tvOS method if needed)"); - return YES; -#endif } - (void)cleanup @@ -475,7 +470,10 @@ - (void)updateAccount if ([error.domain isEqualToString:SRGNetworkErrorDomain] && error.code == SRGNetworkErrorHTTP && [error.userInfo[SRGNetworkHTTPStatusCodeKey] integerValue] == 401) { dispatch_async(dispatch_get_main_queue(), ^{ [self cleanup]; + +#if TARGET_OS_IOS [self dismissAccountView]; +#endif [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification object:self @@ -496,11 +494,12 @@ - (void)updateAccount self.accountRequest = accountRequest; } +#if TARGET_OS_IOS + #pragma mark Account view - (void)showAccountView { -#if TARGET_OS_IOS NSAssert(NSThread.isMainThread, @"Must be called from the main thread"); NSURLRequest *URLRequest = [self accountPresentationRequest]; @@ -526,9 +525,6 @@ - (void)showAccountView [topViewController presentViewController:accountNavigationController animated:YES completion:nil]; self.accountNavigationController = accountNavigationController; -#else - NSAssert(NO, @"TODO: Implement or make it unavailable for tvOS (and add tvOS method if needed)"); -#endif } - (void)dismissAccountView @@ -558,6 +554,13 @@ - (NSURLRequest *)accountPresentationRequest return request.copy; } +- (void)dismissAccountView:(id)sender +{ + [self dismissAccountView]; +} + +#endif + #pragma mark Unauthorization reporting - (void)reportUnauthorization @@ -579,7 +582,10 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL if ([action isEqualToString:@"unauthorized"]) { [self.accountRequest cancel]; [self cleanup]; + +#if TARGET_OS_IOS [self dismissAccountView]; +#endif if (wasLoggedIn) { [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification @@ -591,7 +597,10 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL else if ([action isEqualToString:@"log_out"]) { [self.accountRequest cancel]; [self cleanup]; + +#if TARGET_OS_IOS [self dismissAccountView]; +#endif if (wasLoggedIn) { [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification @@ -603,7 +612,10 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL else if ([action isEqualToString:@"account_deleted"]) { [self.accountRequest cancel]; [self cleanup]; + +#if TARGET_OS_IOS [self dismissAccountView]; +#endif if (wasLoggedIn) { [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification @@ -654,13 +666,6 @@ - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller #endif -#pragma mark Actions - -- (void)dismissAccountView:(id)sender -{ - [self dismissAccountView]; -} - #pragma mark Notifications - (void)reachabilityDidChange:(NSNotification *)notification From 91d6fad1e3915bde13901f159629a946c31514e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 12 Dec 2019 16:48:30 +0100 Subject: [PATCH 30/55] Add sign up instructions --- .../Login/SRGIdentityLoginViewController~tvos.m | 4 ++++ .../SRGIdentityLoginViewController~tvos.storyboard | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index de9f761..2b2c3e3 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -22,6 +22,8 @@ @interface SRGIdentityLoginViewController () @property (nonatomic, weak) IBOutlet UITextField *emailAddressTextField; @property (nonatomic, weak) IBOutlet UITextField *passwordTextField; +@property (nonatomic, weak) IBOutlet UILabel *instructionsLabel; + @property (nonatomic, weak) SRGRequest *loginRequest; @end @@ -56,6 +58,8 @@ - (void)viewDidLoad self.emailAddressTextField.placeholder = SRGIdentityLocalizedString(@"Email address", @"Email address text field placeholder"); self.passwordTextField.placeholder = SRGIdentityLocalizedString(@"Password", @"Password text field placeholder"); + + self.instructionsLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Visit %@ on another device to sign up", @"Instructions for signup on Apple TV (visit a website on another device)"), self.websiteURL.absoluteString]; } - (void)viewDidDisappear:(BOOL)animated diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index f66bb49..37db15f 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -45,11 +45,22 @@ + + + @@ -59,6 +70,7 @@ + From cdd19d3c9038b5e049b38383e68c77e4b73e458f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 11:24:59 +0100 Subject: [PATCH 31/55] Improve login view The maRTS logo is currently hardcoded. maRTS is the only service we use yet, and login will change in the future, so it would be a bit early to introduce a generic mechanism. --- .../Resources/Images.xcassets/Contents.json | 6 ++ .../marts.imageset/Contents.json | 12 +++ .../Images.xcassets/marts.imageset/marts.pdf | Bin 0 -> 10075 bytes .../SRGIdentityLoginViewController~tvos.m | 9 +- ...dentityLoginViewController~tvos.storyboard | 86 +++++++++++------- SRGIdentity.xcodeproj/project.pbxproj | 6 +- 6 files changed, 82 insertions(+), 37 deletions(-) create mode 100644 Framework/Resources/Images.xcassets/Contents.json create mode 100644 Framework/Resources/Images.xcassets/marts.imageset/Contents.json create mode 100644 Framework/Resources/Images.xcassets/marts.imageset/marts.pdf diff --git a/Framework/Resources/Images.xcassets/Contents.json b/Framework/Resources/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Framework/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Framework/Resources/Images.xcassets/marts.imageset/Contents.json b/Framework/Resources/Images.xcassets/marts.imageset/Contents.json new file mode 100644 index 0000000..4fd9a1b --- /dev/null +++ b/Framework/Resources/Images.xcassets/marts.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "marts.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Framework/Resources/Images.xcassets/marts.imageset/marts.pdf b/Framework/Resources/Images.xcassets/marts.imageset/marts.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3b4f4a05e9f9ca223ba322018c16209dfee8bbf8 GIT binary patch literal 10075 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 GivI!@+7CYf literal 0 HcmV?d00001 diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index 2b2c3e3..e393928 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -59,7 +59,12 @@ - (void)viewDidLoad self.passwordTextField.placeholder = SRGIdentityLocalizedString(@"Password", @"Password text field placeholder"); - self.instructionsLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Visit %@ on another device to sign up", @"Instructions for signup on Apple TV (visit a website on another device)"), self.websiteURL.absoluteString]; + NSMutableAttributedString *instructions = [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV (visit a website on another device)")]; + [instructions appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; + [instructions appendAttributedString:[[NSAttributedString alloc] initWithString:self.websiteURL.absoluteString + attributes:@{ NSForegroundColorAttributeName : UIColor.blueColor }]]; + + self.instructionsLabel.attributedText = instructions.copy; } - (void)viewDidDisappear:(BOOL)animated @@ -89,7 +94,7 @@ - (IBAction)login:(id)sender NSString *password = self.passwordTextField.text; if (password.length == 0) { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") - message:SRGIdentityLocalizedString(@"An password is mandatory", @"Error description when no password has been provided") + message:SRGIdentityLocalizedString(@"A password is mandatory", @"Error description when no password has been provided") preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alertController animated:YES completion:nil]; diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index 37db15f..4e92623 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -20,33 +20,53 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + @@ -79,4 +94,7 @@ + + + diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index d34e594..23b59e4 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 6F9FFAAC2167924E00F781A0 /* SRGNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */; }; 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; + 6FC7C5A323A3A13E0058349C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FC7C5A223A3A13E0058349C /* Images.xcassets */; }; 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController~ios.storyboard */; }; 6FCBBD5A221DB644003CE752 /* SRGIdentityNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */; }; 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController~ios.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */; }; @@ -158,6 +159,7 @@ 6FB74D672101D4D200E2D365 /* SRGIdentity-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SRGIdentity-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdentityServiceTestCase.m; sourceTree = ""; }; 6FB74D762101D5D600E2D365 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6FC7C5A223A3A13E0058349C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRGIdentityNavigationController.h; sourceTree = ""; }; 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityNavigationController~ios.m"; sourceTree = ""; }; 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController~ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityWebViewController~ios.m"; sourceTree = ""; }; @@ -415,8 +417,9 @@ 6FCBFEF6210B571C006BC355 /* Resources */ = { isa = PBXGroup; children = ( - 6F19DA7D221DF6E100085C7D /* Localizable.strings */, + 6FC7C5A223A3A13E0058349C /* Images.xcassets */, 083FBD9D217A84D60025253D /* Info.plist */, + 6F19DA7D221DF6E100085C7D /* Localizable.strings */, ); path = Resources; sourceTree = ""; @@ -621,6 +624,7 @@ buildActionMask = 2147483647; files = ( 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */, + 6FC7C5A323A3A13E0058349C /* Images.xcassets in Resources */, 6F9A1FE023A27199002ECFC8 /* SRGIdentityLoginViewController~tvos.storyboard in Resources */, 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */, ); From 0ea8568ee3f837505c6869b06d75d10d45d5038a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 11:49:54 +0100 Subject: [PATCH 32/55] Factor out login request --- .../SRGIdentityLoginViewController~tvos.m | 92 ++++++++++++------- ...dentityLoginViewController~tvos.storyboard | 1 + 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index e393928..5bc146c 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -21,6 +21,7 @@ @interface SRGIdentityLoginViewController () @property (nonatomic, weak) IBOutlet UITextField *emailAddressTextField; @property (nonatomic, weak) IBOutlet UITextField *passwordTextField; +@property (nonatomic, weak) IBOutlet UIButton *loginButton; @property (nonatomic, weak) IBOutlet UILabel *instructionsLabel; @@ -77,29 +78,13 @@ - (void)viewDidDisappear:(BOOL)animated } } -#pragma mark Actions +#pragma mark Requests -- (IBAction)login:(id)sender +- (SRGRequest *)loginRequestWithEmailAddress:(NSString *)emailAddress password:(NSString *)password completionHandler:(void (^)(NSString * _Nullable sessionToken, NSError * _Nullable error))completionHandler { - NSString *emailAddress = self.emailAddressTextField.text; - if (emailAddress.length == 0) { - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") - message:SRGIdentityLocalizedString(@"An email address is mandatory", @"Error description when no email address has been provided") - preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; - [self presentViewController:alertController animated:YES completion:nil]; - return; - } - - NSString *password = self.passwordTextField.text; - if (password.length == 0) { - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") - message:SRGIdentityLocalizedString(@"A password is mandatory", @"Error description when no password has been provided") - preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; - [self presentViewController:alertController animated:YES completion:nil]; - return; - } + NSParameterAssert(emailAddress); + NSParameterAssert(password); + NSParameterAssert(completionHandler); NSURL *URL = [self.webserviceURL URLByAppendingPathComponent:@"v1/login"]; NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL]; @@ -114,20 +99,14 @@ - (IBAction)login:(id)sender [URLRequest setValue:@(HTTPBody.length).stringValue forHTTPHeaderField:@"Content-Length"]; URLRequest.HTTPBody = HTTPBody; - SRGRequest *loginRequest = [SRGRequest dataRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - void (^showError)(NSError *) = ^(NSError *error) { - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error", "Title of a generic error alert") - message:error.localizedDescription - preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; - [self presentViewController:alertController animated:YES completion:nil]; - }; - + return [SRGRequest dataRequestWithURLRequest:URLRequest session:NSURLSession.sharedSession completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { - showError(error); + completionHandler(nil, error); return; } + // Even if credentials are invalid, the request ends with a 200. Only if credentials are valid, though, we find the session token + // in the response cookies. NSString *sessionToken = nil; if ([response isKindOfClass:NSHTTPURLResponse.class]) { NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; @@ -140,16 +119,61 @@ - (IBAction)login:(id)sender } if (! sessionToken) { - // TODO: Proper error NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:401 userInfo:@{ NSLocalizedDescriptionKey : SRGIdentityLocalizedString(@"Wrong email address or password", @"Error message displayed when incorrect user credentials have been supplied") }]; - showError(error); + completionHandler(nil, error); return; } - self.tokenBlock(sessionToken); + completionHandler(sessionToken, nil); }]; +} + +#pragma mark Actions + +- (IBAction)login:(id)sender +{ + NSString *emailAddress = self.emailAddressTextField.text; + if (emailAddress.length == 0) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") + message:SRGIdentityLocalizedString(@"An email address is mandatory", @"Error description when no email address has been provided") + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + return; + } + + NSString *password = self.passwordTextField.text; + if (password.length == 0) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") + message:SRGIdentityLocalizedString(@"A password is mandatory", @"Error description when no password has been provided") + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + return; + } + + self.loginButton.enabled = NO; + + SRGRequest *loginRequest = [[self loginRequestWithEmailAddress:emailAddress password:password completionHandler:^(NSString * _Nullable sessionToken, NSError * _Nullable error) { + self.loginButton.enabled = YES; + + if (error) { + if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) { + return; + } + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error", "Title of a generic error alert") + message:error.localizedDescription + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + return; + } + + self.tokenBlock(sessionToken); + }] requestWithOptions:SRGRequestOptionCancellationErrorsEnabled]; [loginRequest resume]; self.loginRequest = loginRequest; } diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index 4e92623..ddb8037 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -86,6 +86,7 @@ + From c66846d11e9a1a92d916085112c3ed4775acddb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 12:07:23 +0100 Subject: [PATCH 33/55] Use official SRG SSR fonts --- Cartfile | 1 + Cartfile.resolved | 1 + .../SRGIdentityLoginViewController~tvos.m | 7 ++++++ ...dentityLoginViewController~tvos.storyboard | 8 +++---- SRGIdentity.xcodeproj/project.pbxproj | 22 +++++++++++++++++++ docs/README.md | 1 + 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Cartfile b/Cartfile index de16841..f236f3a 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,5 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" +github "SRGSSR/srgappearance-ios" "f2a5f02345db10487d424ff03c45cf193d0c12cf" github "SRGSSR/srgnetwork-ios" "295b641dada5c26ef615bf88d7a3f99609175f00" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index fd26eef..c4c1067 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -4,5 +4,6 @@ github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" +github "SRGSSR/srgappearance-ios" "f2a5f02345db10487d424ff03c45cf193d0c12cf" github "SRGSSR/srglogger-ios" "5df2c5599a2664cd23683fdec225567d8d3ec1ba" github "SRGSSR/srgnetwork-ios" "295b641dada5c26ef615bf88d7a3f99609175f00" diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index 5bc146c..8f4bceb 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -8,6 +8,7 @@ #import "NSBundle+SRGIdentity.h" +#import #import @interface SRGIdentityLoginViewController () @@ -57,8 +58,12 @@ - (void)viewDidLoad self.emailAddressTextField.text = self.emailAddress; self.emailAddressTextField.placeholder = SRGIdentityLocalizedString(@"Email address", @"Email address text field placeholder"); + self.emailAddressTextField.font = [UIFont srg_regularFontWithSize:42.f]; self.passwordTextField.placeholder = SRGIdentityLocalizedString(@"Password", @"Password text field placeholder"); + self.passwordTextField.font = [UIFont srg_regularFontWithSize:42.f]; + + self.loginButton.titleLabel.font = [UIFont srg_regularFontWithSize:36.f]; NSMutableAttributedString *instructions = [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV (visit a website on another device)")]; [instructions appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; @@ -66,6 +71,8 @@ - (void)viewDidLoad attributes:@{ NSForegroundColorAttributeName : UIColor.blueColor }]]; self.instructionsLabel.attributedText = instructions.copy; + self.instructionsLabel.font = [UIFont srg_regularFontWithSize:30.f]; + } - (void)viewDidDisappear:(BOOL)animated diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index ddb8037..c76ff5e 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -33,7 +33,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -66,11 +66,11 @@ diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 23b59e4..73e1c83 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -45,6 +45,8 @@ 6FB74D6C2101D4D200E2D365 /* SRGIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F0EB53120FC7F58009C02CF /* SRGIdentity.framework */; }; 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; 6FC7C5A323A3A13E0058349C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FC7C5A223A3A13E0058349C /* Images.xcassets */; }; + 6FC7C5A523A3A6D80058349C /* SRGAppearance.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FC7C5A423A3A6D70058349C /* SRGAppearance.framework */; }; + 6FC7C5A623A3A6D80058349C /* SRGAppearance.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6FC7C5A423A3A6D70058349C /* SRGAppearance.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController~ios.storyboard */; }; 6FCBBD5A221DB644003CE752 /* SRGIdentityNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */; }; 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController~ios.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */; }; @@ -97,6 +99,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + 6FC7C5A723A3A6D80058349C /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 6FC7C5A623A3A6D80058349C /* SRGAppearance.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -160,6 +173,7 @@ 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdentityServiceTestCase.m; sourceTree = ""; }; 6FB74D762101D5D600E2D365 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6FC7C5A223A3A13E0058349C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 6FC7C5A423A3A6D70058349C /* SRGAppearance.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SRGAppearance.framework; path = Carthage/Build/iOS/SRGAppearance.framework; sourceTree = ""; }; 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRGIdentityNavigationController.h; sourceTree = ""; }; 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityNavigationController~ios.m"; sourceTree = ""; }; 6FF846A0221BED95006FC3FC /* SRGIdentityWebViewController~ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SRGIdentityWebViewController~ios.m"; sourceTree = ""; }; @@ -195,6 +209,7 @@ 080D0BE321356CB600AA519A /* MAKVONotificationCenter.framework in Frameworks */, 080D0BDA21356A1200AA519A /* UICKeyChainStore.framework in Frameworks */, 084CD6FF21696C0A00905A38 /* SRGLogger.framework in Frameworks */, + 6FC7C5A523A3A6D80058349C /* SRGAppearance.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -376,6 +391,7 @@ 080D0BE42135776000AA519A /* Mantle.framework */, 08266651216E354000FD8E84 /* OHHTTPStubs.framework */, 080D0BEE2135A6DD00AA519A /* SafariServices.framework */, + 6FC7C5A423A3A6D70058349C /* SRGAppearance.framework */, 084CD6FE21696C0A00905A38 /* SRGLogger.framework */, 6F9FFAAB2167924E00F781A0 /* SRGNetwork.framework */, 080D0BD921356A1200AA519A /* UICKeyChainStore.framework */, @@ -503,6 +519,7 @@ 6F0EB52D20FC7F58009C02CF /* Frameworks */, 6F0EB52E20FC7F58009C02CF /* Headers */, 6F0EB52F20FC7F58009C02CF /* Resources */, + 6FC7C5A723A3A6D80058349C /* Embed Frameworks */, ); buildRules = ( ); @@ -671,6 +688,7 @@ "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/libextobjc.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/MAKVONotificationCenter.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/Mantle.framework", + "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGAppearance.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGLogger.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/SRGNetwork.framework", "$(SRCROOT)/Carthage/Build/$(CARTHAGE_PLATFORM)/UICKeyChainStore.framework", @@ -932,6 +950,7 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)/Static", + "$(PROJECT_DIR)/Carthage/Build/iOS", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1058,6 +1077,7 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)/Static", + "$(PROJECT_DIR)/Carthage/Build/iOS", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1302,6 +1322,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", + "$(PROJECT_DIR)/Carthage/Build/iOS", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1325,6 +1346,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/$(CARTHAGE_PLATFORM)", + "$(PROJECT_DIR)/Carthage/Build/iOS", ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/docs/README.md b/docs/README.md index d4fc8f9..c14d3d9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -32,6 +32,7 @@ The library requires the following frameworks to be added to any target requirin * `libextobjc`: An utility framework. * `MAKVONotificationCenter`: A safe KVO framework. * `Mantle`: The framework used to parse the data. +* `SRGAppearance`: The appearance framework. * `SRGIdentity`: The identity library framework. * `SRGLogger`: The framework used for internal logging. * `SRGNetwork`: A networking framework. From 6bc24ee0acb67ba735877a7799952cf8cabf6cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 12:19:35 +0100 Subject: [PATCH 34/55] Update documentation --- .../Sources/Login/SRGIdentityLoginViewController.h | 7 +++++++ docs/GETTING_STARTED.md | 12 +++++++----- docs/README.md | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController.h b/Framework/Sources/Login/SRGIdentityLoginViewController.h index 98eca5f..a39e00e 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController.h +++ b/Framework/Sources/Login/SRGIdentityLoginViewController.h @@ -8,9 +8,16 @@ NS_ASSUME_NONNULL_BEGIN +/** + * A view controller to be presented modally, allowing a user to enter her credentials. + */ API_AVAILABLE(tvos(9.0)) API_UNAVAILABLE(ios) @interface SRGIdentityLoginViewController : UIViewController +/** + * Instantiate the view controller. The `tokenBlock` is called when a token has been retrieved, whereas the + * `dismissalBlock` is always called when the view controller is dismissed. + */ - (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL emailAddress:(nullable NSString *)emailAddress diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 2fa5ad4..dad4ef9 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -29,11 +29,11 @@ To allow for a user to login, call the `-loginWithEmailAddress:` instance method [SRGIdentityService.currentIdentityService loginWithEmailAddress:nil]; ``` -This presents a sandboxed Safari browser, in which the user can supply her credentials or open an account. A user remains logged in until she logs out. +On iOS this presents a sandboxed Safari browser, in which the user can supply her credentials or open an account. On tvOS a dedicated in-app view is presented, with which currently users can only log in (a message invite them to open an account on a computer or mobile device). A user remains logged in until she logs out. #### Remark -Login occurs within a simple Safari in-app browser by default. Starting with iOS 11, you might prefer using an authentication session, which lets user credentials be shared between your app and Safari, providing automatic login for apps associated with the same identity provider. Before the user can enter her credentials, a system alert will be displayed to inform her about credential sharing. +On iOS, login occurs within a simple Safari in-app browser by default. Starting with iOS 11, you might prefer using an authentication session, which lets user credentials be shared between your app and Safari, providing automatic login for apps associated with the same identity provider. Before the user can enter her credentials, a system alert will be displayed to inform her about credential sharing. To enable this feature, use the corresponding login method when creating the service: @@ -47,7 +47,7 @@ On iOS 10 devices and older, the default Safari in-app browser will be used inst Once a user has successfully logged in, a corresponding session token is available in the keychain. Use the `SRGIdentityService.currentIdentityService.sessionToken` property when you need to retrieve it. -### Account page +### Account page (iOS only) When a user is logged in, its account information can be displayed and edited within your application through a dedicated web page. To display this page, call `-showAccountView`: @@ -55,6 +55,8 @@ When a user is logged in, its account information can be displayed and edited wi [SRGIdentityService.currentIdentityService showAccountView]; ``` +tvOS users must currently manage their account from a computer or mobile device. + ### Logout To logout the current user, simply call `-logout`; @@ -74,8 +76,8 @@ Instead, if you receive an unauthorization error from a third-party service, cal * If still authorized, nothing happens beside an account update. * If confirmed to be unauthorized, the user is automatically logged out. In such cases, the `SRGIdentityServiceUserDidLogoutNotification` notification is sent with `SRGIdentityServiceUnauthorizedKey` set to `@YES` in its `userInfo` dictionary. You can for example use this information to display a corresponding information message to the user. -### Sandboxed Safari browser support +### Sandboxed Safari browser support (iOS only) -Using `SRGIdentityLoginMethodDefault` or `SRGIdentityLoginMethodSafari` login methods, or any login methods with the iOS 9 or iOS 10 support, your application must declares at least one [custom URL scheme](https://developer.apple.com/documentation/uikit/core_app/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app), which is then used by the framework to transfer control back from Safari to your application after successful login. +Using `SRGIdentityLoginMethodDefault` or `SRGIdentityLoginMethodSafari` login methods, or any login methods with the iOS 9 or iOS 10 support, your application must declare at least one [custom URL scheme](https://developer.apple.com/documentation/uikit/core_app/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app), which is then used by the framework to transfer control back from Safari to your application after successful login. If your application uses custom schemes for other purposes, implement the `-application:openURL:options:` application delegate method as usual. If no explicit URL handling is required, implementing this method is not required, as the framework will take care of injecting an implementation at runtime so that URL handling works. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index c14d3d9..f57c8e3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +8,7 @@ The SRG Identity framework is a simple way to authenticate users within SRG SSR ## Compatibility -The library is suitable for applications running on iOS 9 and above. The project is meant to be opened with the latest Xcode version. +The library is suitable for applications running on iOS 9, tvOS 9 and above. The project is meant to be opened with the latest Xcode version. ## Contributing From d9a63bbcde567ca76c6ea6f536b7dad4ad8de9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 12:20:28 +0100 Subject: [PATCH 35/55] Supply maRTS icon with tvOS framework only --- .../Resources/Images.xcassets/marts.imageset/Contents.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Resources/Images.xcassets/marts.imageset/Contents.json b/Framework/Resources/Images.xcassets/marts.imageset/Contents.json index 4fd9a1b..b75695e 100644 --- a/Framework/Resources/Images.xcassets/marts.imageset/Contents.json +++ b/Framework/Resources/Images.xcassets/marts.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "idiom" : "universal", + "idiom" : "tv", "filename" : "marts.pdf" } ], From 6a79192393129fb91c425e65958f5f577576e56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 12:23:57 +0100 Subject: [PATCH 36/55] Add availability attributes --- Framework/Sources/Browser/SRGIdentityModalTransition.h | 1 + Framework/Sources/Browser/SRGIdentityNavigationController.h | 1 + Framework/Sources/Browser/SRGIdentityWebViewController.h | 1 + Framework/Sources/SRGIdentityService.h | 4 ++-- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Framework/Sources/Browser/SRGIdentityModalTransition.h b/Framework/Sources/Browser/SRGIdentityModalTransition.h index ec5f648..0bb09b0 100644 --- a/Framework/Sources/Browser/SRGIdentityModalTransition.h +++ b/Framework/Sources/Browser/SRGIdentityModalTransition.h @@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Manage a custom modal transition. */ +API_UNAVAILABLE(tvos) @interface SRGIdentityModalTransition : NSObject /** diff --git a/Framework/Sources/Browser/SRGIdentityNavigationController.h b/Framework/Sources/Browser/SRGIdentityNavigationController.h index 536fc58..a96e0ab 100644 --- a/Framework/Sources/Browser/SRGIdentityNavigationController.h +++ b/Framework/Sources/Browser/SRGIdentityNavigationController.h @@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN * A simple navigation controller with a custom push from right modal transition, imitating the Safari web view * controller transition. */ +API_UNAVAILABLE(tvos) @interface SRGIdentityNavigationController : UINavigationController @end diff --git a/Framework/Sources/Browser/SRGIdentityWebViewController.h b/Framework/Sources/Browser/SRGIdentityWebViewController.h index d707e6e..2088dc7 100644 --- a/Framework/Sources/Browser/SRGIdentityWebViewController.h +++ b/Framework/Sources/Browser/SRGIdentityWebViewController.h @@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN /** * A basic web view controller class for in-app display. */ +API_UNAVAILABLE(tvos) @interface SRGIdentityWebViewController : UIViewController /** diff --git a/Framework/Sources/SRGIdentityService.h b/Framework/Sources/SRGIdentityService.h index 5e2fc4c..38d6d25 100644 --- a/Framework/Sources/SRGIdentityService.h +++ b/Framework/Sources/SRGIdentityService.h @@ -21,14 +21,14 @@ typedef NS_ENUM(NSInteger, SRGIdentityLoginMethod) { /** * Login is displayed in a dedicated Safari web view. */ - SRGIdentityLoginMethodSafari = SRGIdentityLoginMethodDefault, + SRGIdentityLoginMethodSafari API_UNAVAILABLE(tvos) = SRGIdentityLoginMethodDefault, /** * Use an authentication session when available (iOS 11 and 12 only). User credentials can be shared between your * app and Safari. This makes it possible for a user to automatically authenticate in another app associated with * the same identity provider (if credentials are still available). Note that a system alert will inform the user * about credentials sharing first. */ - SRGIdentityLoginMethodAuthenticationSession + SRGIdentityLoginMethodAuthenticationSession API_UNAVAILABLE(tvos) }; /** From 48ce695ce00d9896e9ec811ed9024623f102737e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 13:33:10 +0100 Subject: [PATCH 37/55] Conditionally remove iOS code from tvOS builds --- Framework/Sources/SRGIdentityService.m | 142 ++++++++++++------------- 1 file changed, 69 insertions(+), 73 deletions(-) diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index e26a408..63a003d 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -63,14 +63,6 @@ return [NSBundle.mainBundle.bundleIdentifier stringByAppendingString:@".account"]; } -static BOOL swizzled_application_openURL_options(id self, SEL _cmd, UIApplication *application, NSURL *URL, NSDictionary *options); - -@interface NSObject (SRGIdentityApplicationDelegateHooks) - -- (BOOL)srg_default_application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options; - -@end - @interface SRGIdentityService () #if TARGET_OS_IOS @@ -91,34 +83,6 @@ @interface SRGIdentityService () @end -__attribute__((constructor)) static void SRGIdentityServiceInit(void) -{ - NSMutableDictionary *originalImplementations = [NSMutableDictionary dictionary]; - - // The `-application:openURL:options:` application delegate method must be available at the time the application is - // instantiated, see https://stackoverflow.com/questions/14696078/runtime-added-applicationopenurl-not-fires. - unsigned int numberOfClasses = 0; - Class *classList = objc_copyClassList(&numberOfClasses); - for (unsigned int i = 0; i < numberOfClasses; ++i) { - Class cls = classList[i]; - if (class_conformsToProtocol(cls, @protocol(UIApplicationDelegate))) { - Method method = class_getInstanceMethod(cls, @selector(application:openURL:options:)); - if (! method) { - method = class_getInstanceMethod(cls, @selector(srg_default_application:openURL:options:)); - class_addMethod(cls, @selector(application:openURL:options:), method_getImplementation(method), method_getTypeEncoding(method)); - } - - NSValue *key = [NSValue valueWithNonretainedObject:cls]; - originalImplementations[key] = [NSValue valueWithPointer:method_getImplementation(method)]; - - class_replaceMethod(cls, @selector(application:openURL:options:), (IMP)swizzled_application_openURL_options, method_getTypeEncoding(method)); - } - } - free(classList); - - s_originalImplementations = originalImplementations.copy; -} - @implementation SRGIdentityService #pragma mark Class methods @@ -133,23 +97,6 @@ + (void)setCurrentIdentityService:(SRGIdentityService *)currentIdentityService s_currentIdentityService = currentIdentityService; } -+ (NSString *)applicationURLScheme -{ - static NSString *URLScheme; - static dispatch_once_t s_onceToken; - dispatch_once(&s_onceToken, ^{ - NSArray *bundleURLTypes = NSBundle.mainBundle.infoDictionary[@"CFBundleURLTypes"]; - NSArray *bundleURLSchemes = bundleURLTypes.firstObject[@"CFBundleURLSchemes"]; - URLScheme = bundleURLSchemes.firstObject; - if (! URLScheme) { - SRGIdentityLogError(@"service", @"No URL scheme declared in your application Info.plist file under the " - "'CFBundleURLTypes' key. The application must at least contain one item with one scheme " - "to allow a correct authentication workflow."); - } - }); - return URLScheme; -} - #pragma mark Object lifecycle - (instancetype)initWithWebserviceURL:(NSURL *)webserviceURL websiteURL:(NSURL *)websiteURL loginMethod:(SRGIdentityLoginMethod)loginMethod @@ -253,8 +200,27 @@ - (void)setSessionToken:(NSString *)sessionToken [self.keyChainStore setString:sessionToken forKey:SRGServiceIdentifierSessionTokenStoreKey()]; } +#if TARGET_OS_IOS + #pragma mark URL handling ++ (NSString *)applicationURLScheme +{ + static NSString *URLScheme; + static dispatch_once_t s_onceToken; + dispatch_once(&s_onceToken, ^{ + NSArray *bundleURLTypes = NSBundle.mainBundle.infoDictionary[@"CFBundleURLTypes"]; + NSArray *bundleURLSchemes = bundleURLTypes.firstObject[@"CFBundleURLSchemes"]; + URLScheme = bundleURLSchemes.firstObject; + if (! URLScheme) { + SRGIdentityLogError(@"service", @"No URL scheme declared in your application Info.plist file under the " + "'CFBundleURLTypes' key. The application must at least contain one item with one scheme " + "to allow a correct authentication workflow."); + } + }); + return URLScheme; +} + - (NSURL *)redirectURL { NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:self.webserviceURL resolvingAgainstBaseURL:NO]; @@ -301,6 +267,8 @@ - (NSString *)queryItemValueFromURL:(NSURL *)URL withName:(NSString *)queryName return queryItem.value; } +#endif + #pragma mark Login / logout - (BOOL)loginWithEmailAddress:(NSString *)emailAddress @@ -494,6 +462,13 @@ - (void)updateAccount self.accountRequest = accountRequest; } +#pragma mark Unauthorization reporting + +- (void)reportUnauthorization +{ + [self updateAccount]; +} + #if TARGET_OS_IOS #pragma mark Account view @@ -559,15 +534,6 @@ - (void)dismissAccountView:(id)sender [self dismissAccountView]; } -#endif - -#pragma mark Unauthorization reporting - -- (void)reportUnauthorization -{ - [self updateAccount]; -} - #pragma mark Callback URL handling - (BOOL)handleCallbackURL:(NSURL *)callbackURL @@ -582,10 +548,7 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL if ([action isEqualToString:@"unauthorized"]) { [self.accountRequest cancel]; [self cleanup]; - -#if TARGET_OS_IOS [self dismissAccountView]; -#endif if (wasLoggedIn) { [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification @@ -597,10 +560,7 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL else if ([action isEqualToString:@"log_out"]) { [self.accountRequest cancel]; [self cleanup]; - -#if TARGET_OS_IOS [self dismissAccountView]; -#endif if (wasLoggedIn) { [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification @@ -612,10 +572,7 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL else if ([action isEqualToString:@"account_deleted"]) { [self.accountRequest cancel]; [self cleanup]; - -#if TARGET_OS_IOS [self dismissAccountView]; -#endif if (wasLoggedIn) { [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLogoutNotification @@ -651,8 +608,6 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL return NO; } -#if TARGET_OS_IOS - #pragma mark SFSafariViewControllerDelegate delegate - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller @@ -692,6 +647,45 @@ - (NSString *)description @end +#if TARGET_OS_IOS + +static BOOL swizzled_application_openURL_options(id self, SEL _cmd, UIApplication *application, NSURL *URL, NSDictionary *options); + +@interface NSObject (SRGIdentityApplicationDelegateHooks) + +- (BOOL)srg_default_application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options; + +@end + +__attribute__((constructor)) static void SRGIdentityServiceInit(void) +{ + NSMutableDictionary *originalImplementations = [NSMutableDictionary dictionary]; + + // The `-application:openURL:options:` application delegate method must be available at the time the application is + // instantiated, see https://stackoverflow.com/questions/14696078/runtime-added-applicationopenurl-not-fires. + unsigned int numberOfClasses = 0; + Class *classList = objc_copyClassList(&numberOfClasses); + for (unsigned int i = 0; i < numberOfClasses; ++i) { + Class cls = classList[i]; + if (class_conformsToProtocol(cls, @protocol(UIApplicationDelegate))) { + Method method = class_getInstanceMethod(cls, @selector(application:openURL:options:)); + if (! method) { + method = class_getInstanceMethod(cls, @selector(srg_default_application:openURL:options:)); + class_addMethod(cls, @selector(application:openURL:options:), method_getImplementation(method), method_getTypeEncoding(method)); + } + + NSValue *key = [NSValue valueWithNonretainedObject:cls]; + originalImplementations[key] = [NSValue valueWithPointer:method_getImplementation(method)]; + + class_replaceMethod(cls, @selector(application:openURL:options:), (IMP)swizzled_application_openURL_options, method_getTypeEncoding(method)); + } + } + free(classList); + + s_originalImplementations = originalImplementations.copy; +} + + @implementation NSObject (SRGIdentityApplicationDelegateHooks) - (BOOL)srg_default_application:(UIApplication *)application openURL:(NSURL *)URL options:(NSDictionary *)options @@ -731,3 +725,5 @@ static BOOL swizzled_application_openURL_options(id self, SEL _cmd, UIApplicatio SRGIdentityLogError(@"service", @"Could not call open URL app delegate original implementation for %@", self); return NO; } + +#endif From efc37a5f27911e204bbbbdae9f1dfadac8be9f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 14:49:52 +0100 Subject: [PATCH 38/55] Fix unit tests for tvOS --- Framework/Sources/SRGIdentityService.m | 154 +++++------ Tests/Sources/IdentityServiceTestCase.m | 338 +++++++++++++----------- 2 files changed, 266 insertions(+), 226 deletions(-) diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index 63a003d..fcf3fae 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -200,75 +200,6 @@ - (void)setSessionToken:(NSString *)sessionToken [self.keyChainStore setString:sessionToken forKey:SRGServiceIdentifierSessionTokenStoreKey()]; } -#if TARGET_OS_IOS - -#pragma mark URL handling - -+ (NSString *)applicationURLScheme -{ - static NSString *URLScheme; - static dispatch_once_t s_onceToken; - dispatch_once(&s_onceToken, ^{ - NSArray *bundleURLTypes = NSBundle.mainBundle.infoDictionary[@"CFBundleURLTypes"]; - NSArray *bundleURLSchemes = bundleURLTypes.firstObject[@"CFBundleURLSchemes"]; - URLScheme = bundleURLSchemes.firstObject; - if (! URLScheme) { - SRGIdentityLogError(@"service", @"No URL scheme declared in your application Info.plist file under the " - "'CFBundleURLTypes' key. The application must at least contain one item with one scheme " - "to allow a correct authentication workflow."); - } - }); - return URLScheme; -} - -- (NSURL *)redirectURL -{ - NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:self.webserviceURL resolvingAgainstBaseURL:NO]; - URLComponents.scheme = [SRGIdentityService applicationURLScheme]; - URLComponents.queryItems = @[ [[NSURLQueryItem alloc] initWithName:SRGIdentityServiceQueryItemName value:self.identifier] ]; - return URLComponents.URL; -} - -- (NSURL *)loginRequestURLWithEmailAddress:(NSString *)emailAddress -{ - NSURL *redirectURL = [self redirectURL]; - - NSURL *URL = [self.websiteURL URLByAppendingPathComponent:@"login"]; - NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO]; - NSArray *queryItems = @[ [[NSURLQueryItem alloc] initWithName:@"redirect" value:redirectURL.absoluteString] ]; - if (emailAddress) { - NSURLQueryItem *emailQueryItem = [[NSURLQueryItem alloc] initWithName:@"email" value:emailAddress]; - queryItems = [queryItems arrayByAddingObject:emailQueryItem]; - } - URLComponents.queryItems = queryItems; - return URLComponents.URL; -} - -- (BOOL)shouldHandleCallbackURL:(NSURL *)URL -{ - NSURL *standardizedURL = URL.standardizedURL; - NSURL *standardizedRedirectURL = [self redirectURL].standardizedURL; - - NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:YES]; - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @keypath(NSURLQueryItem.new, name), SRGIdentityServiceQueryItemName]; - NSURLQueryItem *queryItem = [URLComponents.queryItems filteredArrayUsingPredicate:predicate].firstObject; - - return [standardizedURL.scheme isEqualToString:standardizedRedirectURL.scheme] - && [standardizedURL.host isEqualToString:standardizedRedirectURL.host] - && [standardizedURL.path isEqual:standardizedRedirectURL.path] - && [self.identifier isEqualToString:queryItem.value]; -} - -- (NSString *)queryItemValueFromURL:(NSURL *)URL withName:(NSString *)queryName -{ - NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO]; - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @keypath(NSURLQueryItem.new, name), queryName]; - NSURLQueryItem *queryItem = [URLComponents.queryItems filteredArrayUsingPredicate:predicate].firstObject; - return queryItem.value; -} - -#endif - #pragma mark Login / logout - (BOOL)loginWithEmailAddress:(NSString *)emailAddress @@ -346,12 +277,7 @@ - (BOOL)loginWithEmailAddress:(NSString *)emailAddress UIViewController *topViewController = UIApplication.sharedApplication.keyWindow.srgidentity_topViewController; SRGIdentityLoginViewController *loginViewController = [[SRGIdentityLoginViewController alloc] initWithWebserviceURL:self.webserviceURL websiteURL:self.websiteURL emailAddress:emailAddress tokenBlock:^(NSString * _Nonnull sessionToken) { [topViewController dismissViewControllerAnimated:YES completion:nil]; - - self.sessionToken = sessionToken; - [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLoginNotification - object:self - userInfo:nil]; - [self updateAccount]; + [self handleSessionToken:sessionToken]; } dismissalBlock:^{ s_loggingIn = NO; }]; @@ -471,6 +397,71 @@ - (void)reportUnauthorization #if TARGET_OS_IOS +#pragma mark URL handling + ++ (NSString *)applicationURLScheme +{ + static NSString *URLScheme; + static dispatch_once_t s_onceToken; + dispatch_once(&s_onceToken, ^{ + NSArray *bundleURLTypes = NSBundle.mainBundle.infoDictionary[@"CFBundleURLTypes"]; + NSArray *bundleURLSchemes = bundleURLTypes.firstObject[@"CFBundleURLSchemes"]; + URLScheme = bundleURLSchemes.firstObject; + if (! URLScheme) { + SRGIdentityLogError(@"service", @"No URL scheme declared in your application Info.plist file under the " + "'CFBundleURLTypes' key. The application must at least contain one item with one scheme " + "to allow a correct authentication workflow."); + } + }); + return URLScheme; +} + +- (NSURL *)redirectURL +{ + NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:self.webserviceURL resolvingAgainstBaseURL:NO]; + URLComponents.scheme = [SRGIdentityService applicationURLScheme]; + URLComponents.queryItems = @[ [[NSURLQueryItem alloc] initWithName:SRGIdentityServiceQueryItemName value:self.identifier] ]; + return URLComponents.URL; +} + +- (NSURL *)loginRequestURLWithEmailAddress:(NSString *)emailAddress +{ + NSURL *redirectURL = [self redirectURL]; + + NSURL *URL = [self.websiteURL URLByAppendingPathComponent:@"login"]; + NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO]; + NSArray *queryItems = @[ [[NSURLQueryItem alloc] initWithName:@"redirect" value:redirectURL.absoluteString] ]; + if (emailAddress) { + NSURLQueryItem *emailQueryItem = [[NSURLQueryItem alloc] initWithName:@"email" value:emailAddress]; + queryItems = [queryItems arrayByAddingObject:emailQueryItem]; + } + URLComponents.queryItems = queryItems; + return URLComponents.URL; +} + +- (BOOL)shouldHandleCallbackURL:(NSURL *)URL +{ + NSURL *standardizedURL = URL.standardizedURL; + NSURL *standardizedRedirectURL = [self redirectURL].standardizedURL; + + NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:YES]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @keypath(NSURLQueryItem.new, name), SRGIdentityServiceQueryItemName]; + NSURLQueryItem *queryItem = [URLComponents.queryItems filteredArrayUsingPredicate:predicate].firstObject; + + return [standardizedURL.scheme isEqualToString:standardizedRedirectURL.scheme] + && [standardizedURL.host isEqualToString:standardizedRedirectURL.host] + && [standardizedURL.path isEqual:standardizedRedirectURL.path] + && [self.identifier isEqualToString:queryItem.value]; +} + +- (NSString *)queryItemValueFromURL:(NSURL *)URL withName:(NSString *)queryName +{ + NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @keypath(NSURLQueryItem.new, name), queryName]; + NSURLQueryItem *queryItem = [URLComponents.queryItems filteredArrayUsingPredicate:predicate].firstObject; + return queryItem.value; +} + #pragma mark Account view - (void)showAccountView @@ -619,6 +610,19 @@ - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller userInfo:nil]; } +#else + +#pragma mark Token handling + +- (void)handleSessionToken:(NSString *)sessionToken +{ + self.sessionToken = sessionToken; + [[NSNotificationCenter defaultCenter] postNotificationName:SRGIdentityServiceUserDidLoginNotification + object:self + userInfo:nil]; + [self updateAccount]; +} + #endif #pragma mark Notifications diff --git a/Tests/Sources/IdentityServiceTestCase.m b/Tests/Sources/IdentityServiceTestCase.m index 4c8e7f2..5311176 100644 --- a/Tests/Sources/IdentityServiceTestCase.m +++ b/Tests/Sources/IdentityServiceTestCase.m @@ -9,18 +9,8 @@ #import #import -#if TARGET_OS_IOS - static NSString *TestValidToken = @"0123456789"; -@interface SRGIdentityService (Private) - -- (BOOL)handleCallbackURL:(NSURL *)callbackURL; - -@property (nonatomic, readonly, copy) NSString *identifier; - -@end - static NSURL *TestWebserviceURL(void) { return [NSURL URLWithString:@"https://api.srgssr.local"]; @@ -31,6 +21,16 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL; return [NSURL URLWithString:@"https://www.srgssr.local"]; } +#if TARGET_OS_IOS + +@interface SRGIdentityService (Private) + +- (BOOL)handleCallbackURL:(NSURL *)callbackURL; + +@property (nonatomic, readonly, copy) NSString *identifier; + +@end + static NSURL *TestLoginCallbackURL(SRGIdentityService *identityService, NSString *token) { NSString *URLString = [NSString stringWithFormat:@"srgidentity-tests://%@?identity_service=%@&token=%@", TestWebserviceURL().host, identityService.identifier, token]; @@ -73,6 +73,16 @@ - (BOOL)handleCallbackURL:(NSURL *)callbackURL; return [NSURL URLWithString:URLString]; } +#else + +@interface SRGIdentityService (Private) + +- (BOOL)handleSessionToken:(NSString *)sessionToken; + +@end + +#endif + @interface IdentityServiceTestCase : IdentityBaseTestCase @property (nonatomic) SRGIdentityService *identityService; @@ -154,7 +164,7 @@ - (void)tearDown #pragma mark Tests -- (void)testLoginHandleCallbackURL +- (void)testLogin { XCTAssertNil(self.identityService.emailAddress); XCTAssertNil(self.identityService.sessionToken); @@ -167,8 +177,12 @@ - (void)testLoginHandleCallbackURL return YES; }]; +#if TARGET_OS_IOS BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; XCTAssertTrue(hasHandledCallbackURL); +#else + [self.identityService handleSessionToken:TestValidToken]; +#endif [self waitForExpectationsWithTimeout:5. handler:nil]; @@ -179,7 +193,7 @@ - (void)testLoginHandleCallbackURL XCTAssertTrue(self.identityService.loggedIn); } -- (void)testLogoutHandleCallbackURL +- (void)testLogout { XCTAssertNil(self.identityService.emailAddress); XCTAssertNil(self.identityService.sessionToken); @@ -192,7 +206,11 @@ - (void)testLogoutHandleCallbackURL return YES; }]; +#if TARGET_OS_IOS [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; +#else + [self.identityService handleSessionToken:TestValidToken]; +#endif [self waitForExpectationsWithTimeout:5. handler:nil]; @@ -205,19 +223,20 @@ - (void)testLogoutHandleCallbackURL return YES; }]; - BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestLogoutCallbackURL(self.identityService)]; - XCTAssertTrue(hasHandledCallbackURL); - - [self waitForExpectationsWithTimeout:5. handler:nil]; + XCTAssertTrue([self.identityService logout]); XCTAssertNil(self.identityService.emailAddress); XCTAssertNil(self.identityService.sessionToken); XCTAssertNil(self.identityService.account); XCTAssertFalse(self.identityService.loggedIn); + + [self waitForExpectationsWithTimeout:5. handler:nil]; + + XCTAssertFalse([self.identityService logout]); } -- (void)testAccountDeletedHandleCallbackURL +- (void)testAccountUpdate { XCTAssertNil(self.identityService.emailAddress); XCTAssertNil(self.identityService.sessionToken); @@ -230,22 +249,44 @@ - (void)testAccountDeletedHandleCallbackURL return YES; }]; +#if TARGET_OS_IOS [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; +#else + [self.identityService handleSessionToken:TestValidToken]; +#endif [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertTrue(self.identityService.loggedIn); + + [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertNotNil(notification.userInfo[SRGIdentityServiceAccountKey]); + XCTAssertNil(notification.userInfo[SRGIdentityServicePreviousAccountKey]); + return YES; + }]; + + [self waitForExpectationsWithTimeout:5. handler:nil]; + + XCTAssertNotNil(self.identityService.emailAddress); XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); + XCTAssertNotNil(self.identityService.account); + + XCTAssertTrue(self.identityService.loggedIn); [self expectationForSingleNotification:SRGIdentityServiceUserDidLogoutNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { XCTAssertTrue([NSThread isMainThread]); XCTAssertFalse([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); - XCTAssertTrue([notification.userInfo[SRGIdentityServiceDeletedKey] boolValue]); + return YES; + }]; + [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertNil(notification.userInfo[SRGIdentityServiceAccountKey]); + XCTAssertNotNil(notification.userInfo[SRGIdentityServicePreviousAccountKey]); return YES; }]; - BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestAccountDeletedCallbackURL(self.identityService)]; - XCTAssertTrue(hasHandledCallbackURL); + XCTAssertTrue([self.identityService logout]); [self waitForExpectationsWithTimeout:5. handler:nil]; @@ -256,35 +297,29 @@ - (void)testAccountDeletedHandleCallbackURL XCTAssertFalse(self.identityService.loggedIn); } -- (void)testUnauthorizedHandleCallbackURL +- (void)testAutomaticLogoutWhenUnauthorized { - XCTAssertNil(self.identityService.emailAddress); - XCTAssertNil(self.identityService.sessionToken); - XCTAssertNil(self.identityService.account); - - XCTAssertFalse(self.identityService.loggedIn); - [self expectationForSingleNotification:SRGIdentityServiceUserDidLoginNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); return YES; }]; - [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; +#if TARGET_OS_IOS + [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, @"invalid_token")]; +#else + [self.identityService handleSessionToken:@"invalid_token"]; +#endif [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertTrue(self.identityService.loggedIn); - XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); + XCTAssertEqualObjects(self.identityService.sessionToken, @"invalid_token"); + // Wait until account information is requested. The token is invalid, the user unauthorized and therefore logged out automatically [self expectationForSingleNotification:SRGIdentityServiceUserDidLogoutNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); XCTAssertTrue([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); return YES; }]; - BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestUnauthorizedCallbackURL(self.identityService)]; - XCTAssertTrue(hasHandledCallbackURL); - [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertNil(self.identityService.emailAddress); @@ -294,38 +329,33 @@ - (void)testUnauthorizedHandleCallbackURL XCTAssertFalse(self.identityService.loggedIn); } -- (void)testIgnoredHandleCallbackURL +- (void)testUnverifiedReportedUnauthorization { - XCTAssertNil(self.identityService.emailAddress); - XCTAssertNil(self.identityService.sessionToken); - XCTAssertNil(self.identityService.account); - - XCTAssertFalse(self.identityService.loggedIn); - [self expectationForSingleNotification:SRGIdentityServiceUserDidLoginNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); return YES; }]; +#if TARGET_OS_IOS [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; +#else + [self.identityService handleSessionToken:TestValidToken]; +#endif [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertTrue(self.identityService.loggedIn); XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); - [self expectationForElapsedTimeInterval:4. withHandler:nil]; - id logoutObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceUserDidLogoutNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { XCTFail(@"No logout is expected"); }]; - BOOL hasHandledCallbackURL1 = [self.identityService handleCallbackURL:TestIgnored1CallbackURL(self.identityService)]; - XCTAssertFalse(hasHandledCallbackURL1); - BOOL hasHandledCallbackURL2 = [self.identityService handleCallbackURL:TestIgnored2CallbackURL(self.identityService)]; - XCTAssertFalse(hasHandledCallbackURL2); - BOOL hasHandledCallbackURL3 = [self.identityService handleCallbackURL:TestIgnored3CallbackURL()]; - XCTAssertFalse(hasHandledCallbackURL3); + [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + return YES; + }]; + [self expectationForElapsedTimeInterval:4. withHandler:nil]; + + [self.identityService reportUnauthorization]; [self waitForExpectationsWithTimeout:5. handler:^(NSError * _Nullable error) { [NSNotificationCenter.defaultCenter removeObserver:logoutObserver]; @@ -335,46 +365,77 @@ - (void)testIgnoredHandleCallbackURL XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); } -- (void)testLogout +- (void)testMultipleUnverifiedReportedUnauthorizations { - XCTAssertNil(self.identityService.emailAddress); - XCTAssertNil(self.identityService.sessionToken); - XCTAssertNil(self.identityService.account); - - XCTAssertFalse(self.identityService.loggedIn); - - [self expectationForSingleNotification:SRGIdentityServiceUserDidLoginNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); + // A first account update is performed after login. Wait for it + [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { return YES; }]; +#if TARGET_OS_IOS [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; +#else + [self.identityService handleSessionToken:TestValidToken]; +#endif [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertTrue(self.identityService.loggedIn); XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); - [self expectationForSingleNotification:SRGIdentityServiceUserDidLogoutNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertFalse([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); - return YES; + __block NSInteger numberOfUpdates = 0; + id accountUpdateObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { + ++numberOfUpdates; }]; - XCTAssertTrue([self.identityService logout]); + [self expectationForElapsedTimeInterval:4. withHandler:nil]; - XCTAssertNil(self.identityService.emailAddress); - XCTAssertNil(self.identityService.sessionToken); - XCTAssertNil(self.identityService.account); + // Unverified reported unauthorizations lead to an account update. Expect at most 1 + [self.identityService reportUnauthorization]; + [self.identityService reportUnauthorization]; + [self.identityService reportUnauthorization]; + [self.identityService reportUnauthorization]; + [self.identityService reportUnauthorization]; + + [self waitForExpectationsWithTimeout:5. handler:^(NSError * _Nullable error) { + [NSNotificationCenter.defaultCenter removeObserver:accountUpdateObserver]; + }]; + XCTAssertEqual(numberOfUpdates, 1); +} + +- (void)testReportedUnauthorizationWhenLoggedOut +{ XCTAssertFalse(self.identityService.loggedIn); + XCTAssertNil(self.identityService.sessionToken); - [self waitForExpectationsWithTimeout:5. handler:nil]; + id loginObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceUserDidLoginNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { + XCTFail(@"No login is expected"); + }]; + id accountUpdateObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { + XCTFail(@"No account update is expected"); + }]; + id logoutObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceUserDidLogoutNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { + XCTFail(@"No logout is expected"); + }]; - XCTAssertFalse([self.identityService logout]); + [self expectationForElapsedTimeInterval:4. withHandler:nil]; + + [self.identityService reportUnauthorization]; + + [self waitForExpectationsWithTimeout:5. handler:^(NSError * _Nullable error) { + [NSNotificationCenter.defaultCenter removeObserver:loginObserver]; + [NSNotificationCenter.defaultCenter removeObserver:accountUpdateObserver]; + [NSNotificationCenter.defaultCenter removeObserver:logoutObserver]; + }]; + + XCTAssertFalse(self.identityService.loggedIn); + XCTAssertNil(self.identityService.sessionToken); } -- (void)testAccountUpdate +#if TARGET_OS_IOS + +- (void)testLogoutHandleCallbackURL { XCTAssertNil(self.identityService.emailAddress); XCTAssertNil(self.identityService.sessionToken); @@ -392,35 +453,16 @@ - (void)testAccountUpdate [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertTrue(self.identityService.loggedIn); - - [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertNotNil(notification.userInfo[SRGIdentityServiceAccountKey]); - XCTAssertNil(notification.userInfo[SRGIdentityServicePreviousAccountKey]); - return YES; - }]; - - [self waitForExpectationsWithTimeout:5. handler:nil]; - - XCTAssertNotNil(self.identityService.emailAddress); XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); - XCTAssertNotNil(self.identityService.account); - - XCTAssertTrue(self.identityService.loggedIn); [self expectationForSingleNotification:SRGIdentityServiceUserDidLogoutNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { XCTAssertTrue([NSThread isMainThread]); XCTAssertFalse([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); return YES; }]; - [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([NSThread isMainThread]); - XCTAssertNil(notification.userInfo[SRGIdentityServiceAccountKey]); - XCTAssertNotNil(notification.userInfo[SRGIdentityServicePreviousAccountKey]); - return YES; - }]; - XCTAssertTrue([self.identityService logout]); + BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestLogoutCallbackURL(self.identityService)]; + XCTAssertTrue(hasHandledCallbackURL); [self waitForExpectationsWithTimeout:5. handler:nil]; @@ -431,25 +473,36 @@ - (void)testAccountUpdate XCTAssertFalse(self.identityService.loggedIn); } -- (void)testAutomaticLogoutWhenUnauthorized +- (void)testAccountDeletedHandleCallbackURL { + XCTAssertNil(self.identityService.emailAddress); + XCTAssertNil(self.identityService.sessionToken); + XCTAssertNil(self.identityService.account); + + XCTAssertFalse(self.identityService.loggedIn); + [self expectationForSingleNotification:SRGIdentityServiceUserDidLoginNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertTrue([NSThread isMainThread]); return YES; }]; - [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, @"invalid_token")]; + [self.identityService handleCallbackURL:TestLoginCallbackURL(self.identityService, TestValidToken)]; [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertTrue(self.identityService.loggedIn); - XCTAssertEqualObjects(self.identityService.sessionToken, @"invalid_token"); + XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); - // Wait until account information is requested. The token is invalid, the user unauthorized and therefore logged out automatically [self expectationForSingleNotification:SRGIdentityServiceUserDidLogoutNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { - XCTAssertTrue([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); + XCTAssertTrue([NSThread isMainThread]); + XCTAssertFalse([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); + XCTAssertTrue([notification.userInfo[SRGIdentityServiceDeletedKey] boolValue]); return YES; }]; + BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestAccountDeletedCallbackURL(self.identityService)]; + XCTAssertTrue(hasHandledCallbackURL); + [self waitForExpectationsWithTimeout:5. handler:nil]; XCTAssertNil(self.identityService.emailAddress); @@ -459,9 +512,16 @@ - (void)testAutomaticLogoutWhenUnauthorized XCTAssertFalse(self.identityService.loggedIn); } -- (void)testUnverifiedReportedUnauthorization +- (void)testUnauthorizedHandleCallbackURL { + XCTAssertNil(self.identityService.emailAddress); + XCTAssertNil(self.identityService.sessionToken); + XCTAssertNil(self.identityService.account); + + XCTAssertFalse(self.identityService.loggedIn); + [self expectationForSingleNotification:SRGIdentityServiceUserDidLoginNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertTrue([NSThread isMainThread]); return YES; }]; @@ -472,29 +532,34 @@ - (void)testUnverifiedReportedUnauthorization XCTAssertTrue(self.identityService.loggedIn); XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); - id logoutObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceUserDidLogoutNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { - XCTFail(@"No logout is expected"); - }]; - - [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + [self expectationForSingleNotification:SRGIdentityServiceUserDidLogoutNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertTrue([notification.userInfo[SRGIdentityServiceUnauthorizedKey] boolValue]); return YES; }]; - [self expectationForElapsedTimeInterval:4. withHandler:nil]; - [self.identityService reportUnauthorization]; + BOOL hasHandledCallbackURL = [self.identityService handleCallbackURL:TestUnauthorizedCallbackURL(self.identityService)]; + XCTAssertTrue(hasHandledCallbackURL); - [self waitForExpectationsWithTimeout:5. handler:^(NSError * _Nullable error) { - [NSNotificationCenter.defaultCenter removeObserver:logoutObserver]; - }]; + [self waitForExpectationsWithTimeout:5. handler:nil]; - XCTAssertTrue(self.identityService.loggedIn); - XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); + XCTAssertNil(self.identityService.emailAddress); + XCTAssertNil(self.identityService.sessionToken); + XCTAssertNil(self.identityService.account); + + XCTAssertFalse(self.identityService.loggedIn); } -- (void)testMultipleUnverifiedReportedUnauthorizations +- (void)testIgnoredHandleCallbackURL { - // A first account update is performed after login. Wait for it - [self expectationForSingleNotification:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertNil(self.identityService.emailAddress); + XCTAssertNil(self.identityService.sessionToken); + XCTAssertNil(self.identityService.account); + + XCTAssertFalse(self.identityService.loggedIn); + + [self expectationForSingleNotification:SRGIdentityServiceUserDidLoginNotification object:self.identityService handler:^BOOL(NSNotification * _Nonnull notification) { + XCTAssertTrue([NSThread isMainThread]); return YES; }]; @@ -505,56 +570,27 @@ - (void)testMultipleUnverifiedReportedUnauthorizations XCTAssertTrue(self.identityService.loggedIn); XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); - __block NSInteger numberOfUpdates = 0; - id accountUpdateObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { - ++numberOfUpdates; - }]; - [self expectationForElapsedTimeInterval:4. withHandler:nil]; - // Unverified reported unauthorizations lead to an account update. Expect at most 1 - [self.identityService reportUnauthorization]; - [self.identityService reportUnauthorization]; - [self.identityService reportUnauthorization]; - [self.identityService reportUnauthorization]; - [self.identityService reportUnauthorization]; - - [self waitForExpectationsWithTimeout:5. handler:^(NSError * _Nullable error) { - [NSNotificationCenter.defaultCenter removeObserver:accountUpdateObserver]; - }]; - - XCTAssertEqual(numberOfUpdates, 1); -} - -- (void)testReportedUnauthorizationWhenLoggedOut -{ - XCTAssertFalse(self.identityService.loggedIn); - XCTAssertNil(self.identityService.sessionToken); - - id loginObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceUserDidLoginNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { - XCTFail(@"No login is expected"); - }]; - id accountUpdateObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceDidUpdateAccountNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { - XCTFail(@"No account update is expected"); - }]; id logoutObserver = [NSNotificationCenter.defaultCenter addObserverForName:SRGIdentityServiceUserDidLogoutNotification object:self.identityService queue:nil usingBlock:^(NSNotification * _Nonnull note) { XCTFail(@"No logout is expected"); }]; - [self expectationForElapsedTimeInterval:4. withHandler:nil]; - - [self.identityService reportUnauthorization]; + BOOL hasHandledCallbackURL1 = [self.identityService handleCallbackURL:TestIgnored1CallbackURL(self.identityService)]; + XCTAssertFalse(hasHandledCallbackURL1); + BOOL hasHandledCallbackURL2 = [self.identityService handleCallbackURL:TestIgnored2CallbackURL(self.identityService)]; + XCTAssertFalse(hasHandledCallbackURL2); + BOOL hasHandledCallbackURL3 = [self.identityService handleCallbackURL:TestIgnored3CallbackURL()]; + XCTAssertFalse(hasHandledCallbackURL3); [self waitForExpectationsWithTimeout:5. handler:^(NSError * _Nullable error) { - [NSNotificationCenter.defaultCenter removeObserver:loginObserver]; - [NSNotificationCenter.defaultCenter removeObserver:accountUpdateObserver]; [NSNotificationCenter.defaultCenter removeObserver:logoutObserver]; }]; - XCTAssertFalse(self.identityService.loggedIn); - XCTAssertNil(self.identityService.sessionToken); + XCTAssertTrue(self.identityService.loggedIn); + XCTAssertEqualObjects(self.identityService.sessionToken, TestValidToken); } -@end - #endif + +@end From 635a61a704a5693b3be959de251a94c0364a81c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 15:21:40 +0100 Subject: [PATCH 39/55] Extract version information to xcconfig files --- Common.xcconfig | 7 +++++++ SRGIdentity.xcodeproj/project.pbxproj | 12 ------------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Common.xcconfig b/Common.xcconfig index 654f225..54d715d 100644 --- a/Common.xcconfig +++ b/Common.xcconfig @@ -1,3 +1,10 @@ +// Version information +MARKETING_VERSION = 2.0.0 + +// Deployment targets +IPHONEOS_DEPLOYMENT_TARGET = 9.0 +TVOS_DEPLOYMENT_TARGET = 12.0 + // Configuration to have a single target built for all platforms // See https://davedelong.com/blog/2018/11/15/building-a-crossplatform-framework/ SUPPORTED_PLATFORMS = iphoneos iphonesimulator appletvos appletvsimulator diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 73e1c83..78dbe58 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -929,13 +929,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)"; - TVOS_DEPLOYMENT_TARGET = 9.0; }; name = "Debug-static"; }; @@ -1056,12 +1053,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)"; - TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = "Release-static"; @@ -1245,13 +1239,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)"; - TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; @@ -1303,12 +1294,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "ch.srgssr.$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)"; - TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = Release; From 9352f96043bb6b1cb6e162fe3228586fc13c537f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 15:26:25 +0100 Subject: [PATCH 40/55] Fix deprecation warnings --- Framework/Sources/Model/SRGAccount.h | 2 +- Framework/Sources/Model/SRGAccount.m | 7 +++++ Framework/Sources/SRGIdentityService.m | 42 ++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Framework/Sources/Model/SRGAccount.h b/Framework/Sources/Model/SRGAccount.h index 19efcfd..2704e37 100644 --- a/Framework/Sources/Model/SRGAccount.h +++ b/Framework/Sources/Model/SRGAccount.h @@ -33,7 +33,7 @@ typedef NS_ENUM(NSInteger, SRGGender) { /** * Account information. */ -@interface SRGAccount : MTLModel +@interface SRGAccount : MTLModel /** * The unique account identifier. diff --git a/Framework/Sources/Model/SRGAccount.m b/Framework/Sources/Model/SRGAccount.m index 5660753..562378f 100644 --- a/Framework/Sources/Model/SRGAccount.m +++ b/Framework/Sources/Model/SRGAccount.m @@ -44,6 +44,13 @@ + (NSDictionary *)JSONKeyPathsByPropertyKey return s_mapping; } +#pragma mark NSSecureCoding protocol + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + #pragma mark Transformers + (NSValueTransformer *)genderJSONTransformer diff --git a/Framework/Sources/SRGIdentityService.m b/Framework/Sources/SRGIdentityService.m index fcf3fae..01ff684 100644 --- a/Framework/Sources/SRGIdentityService.m +++ b/Framework/Sources/SRGIdentityService.m @@ -63,6 +63,44 @@ return [NSBundle.mainBundle.bundleIdentifier stringByAppendingString:@".account"]; } +// TODO: Use secure unarchiving directly once iOS 11 is the minimum version +static SRGAccount *SRGIdentityAccountFromData(NSData *data) +{ + if (! data) { + return nil; + } + +#if TARGET_OS_TV + return [NSKeyedUnarchiver unarchivedObjectOfClass:SRGAccount.class fromData:data error:NULL]; +#else + if (@available(iOS 11, *)) { + return [NSKeyedUnarchiver unarchivedObjectOfClass:SRGAccount.class fromData:data error:NULL]; + } + else { + return [NSKeyedUnarchiver unarchiveObjectWithData:data]; + } +#endif +} + +// TODO: Use secure archiving directly once iOS 11 is the minimum version +static NSData *SRGIdentityDataFromAccount(SRGAccount *account) +{ + if (! account) { + return nil; + } + +#if TARGET_OS_TV + return [NSKeyedArchiver archivedDataWithRootObject:account requiringSecureCoding:YES error:NULL]; +#else + if (@available(iOS 11, *)) { + return [NSKeyedArchiver archivedDataWithRootObject:account requiringSecureCoding:YES error:NULL]; + } + else { + return [NSKeyedArchiver archivedDataWithRootObject:account]; + } +#endif +} + @interface SRGIdentityService () #if TARGET_OS_IOS @@ -172,7 +210,7 @@ - (void)setEmailAddress:(NSString *)emailAddress - (SRGAccount *)account { NSData *accountData = [self.keyChainStore dataForKey:SRGServiceIdentifierAccountStoreKey()]; - return accountData ? [NSKeyedUnarchiver unarchiveObjectWithData:accountData] : nil; + return SRGIdentityAccountFromData(accountData); } - (void)setAccount:(SRGAccount *)account @@ -180,7 +218,7 @@ - (void)setAccount:(SRGAccount *)account NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; userInfo[SRGIdentityServicePreviousAccountKey] = self.account; - NSData *accountData = account ? [NSKeyedArchiver archivedDataWithRootObject:account] : nil; + NSData *accountData = SRGIdentityDataFromAccount(account); [self.keyChainStore setData:accountData forKey:SRGServiceIdentifierAccountStoreKey()]; userInfo[SRGIdentityServiceAccountKey] = account; From 7d59faa79a6c4e08b08acafd9e744a3e6cc587c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 15:46:40 +0100 Subject: [PATCH 41/55] Update dependencies --- Cartfile | 4 ++-- Cartfile.resolved | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cartfile b/Cartfile index f236f3a..bb149b7 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,5 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" -github "SRGSSR/srgappearance-ios" "f2a5f02345db10487d424ff03c45cf193d0c12cf" -github "SRGSSR/srgnetwork-ios" "295b641dada5c26ef615bf88d7a3f99609175f00" +github "SRGSSR/srgappearance-apple" "77bc6d887110e45957ac5320a2008a649efbf74c" +github "SRGSSR/srgnetwork-apple" "abe8363f55ba72837b2d93d124e6d6475806cfd1" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index c4c1067..b08b1c6 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -4,6 +4,6 @@ github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" -github "SRGSSR/srgappearance-ios" "f2a5f02345db10487d424ff03c45cf193d0c12cf" -github "SRGSSR/srglogger-ios" "5df2c5599a2664cd23683fdec225567d8d3ec1ba" -github "SRGSSR/srgnetwork-ios" "295b641dada5c26ef615bf88d7a3f99609175f00" +github "SRGSSR/srgappearance-apple" "77bc6d887110e45957ac5320a2008a649efbf74c" +github "SRGSSR/srglogger-apple" "40946ee91c53886c1b8c76f7d18be0880dfffb72" +github "SRGSSR/srgnetwork-apple" "abe8363f55ba72837b2d93d124e6d6475806cfd1" From fc085260bbe97507d9be78564fa0e8b2d6e9ba00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 15:49:45 +0100 Subject: [PATCH 42/55] Update documentation --- docs/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index f57c8e3..3b4aded 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -![SRG Media Player logo](README-images/logo.png) +[![SRG Media Player logo](README-images/logo.png)](https://github.com/SRGSSR/srgidentity-apple) -[![GitHub releases](https://img.shields.io/github/v/release/SRGSSR/srgidentity-ios)](https://github.com/SRGSSR/srgidentity-ios/releases) [![platform](https://img.shields.io/badge/platfom-ios-blue)](https://github.com/SRGSSR/srgidentity-ios) [![Build Status](https://travis-ci.org/SRGSSR/srgidentity-ios.svg?branch=master)](https://travis-ci.org/SRGSSR/srgidentity-ios/branches) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![GitHub license](https://img.shields.io/github/license/SRGSSR/srgidentity-ios)](https://github.com/SRGSSR/srgidentity-ios/blob/master/LICENSE) +[![GitHub releases](https://img.shields.io/github/v/release/SRGSSR/srgidentity-apple)](https://github.com/SRGSSR/srgidentity-apple/releases) [![platform](https://img.shields.io/badge/platfom-ios%20%7C%20tvos-blue)](https://github.com/SRGSSR/srgidentity-apple) [![Build Status](https://travis-ci.org/SRGSSR/srgidentity-apple.svg?branch=master)](https://travis-ci.org/SRGSSR/srgidentity-apple/branches) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![GitHub license](https://img.shields.io/github/license/SRGSSR/srgidentity-apple)](https://github.com/SRGSSR/srgidentity-apple/blob/master/LICENSE) ## About @@ -8,7 +8,7 @@ The SRG Identity framework is a simple way to authenticate users within SRG SSR ## Compatibility -The library is suitable for applications running on iOS 9, tvOS 9 and above. The project is meant to be opened with the latest Xcode version. +The library is suitable for applications running on iOS 9, tvOS 12 and above. The project is meant to be opened with the latest Xcode version. ## Contributing @@ -19,7 +19,7 @@ If you want to contribute to the project, have a look at our [contributing guide The library can be added to a project using [Carthage](https://github.com/Carthage/Carthage) by adding the following dependency to your `Cartfile`: ``` -github "SRGSSR/srgidentity-ios" +github "SRGSSR/srgidentity-apple" ``` For more information about Carthage and its use, refer to the [official documentation](https://github.com/Carthage/Carthage). @@ -87,7 +87,7 @@ To learn about how the library can be used, have a look at the [getting started ### Logging -The library internally uses the [SRG Logger](https://github.com/SRGSSR/srglogger-ios) library for logging, within the `ch.srgssr.mediaplayer` subsystem. This logger either automatically integrates with your own logger, or can be easily integrated with it. Refer to the SRG Logger documentation for more information. +The library internally uses the [SRG Logger](https://github.com/SRGSSR/srglogger-apple) library for logging, within the `ch.srgssr.mediaplayer` subsystem. This logger either automatically integrates with your own logger, or can be easily integrated with it. Refer to the SRG Logger documentation for more information. ## License From 51b5f9753f4481dcd177e34185678361e173e277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 13 Dec 2019 21:26:43 +0100 Subject: [PATCH 43/55] Fix link --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 3b4aded..0a6fdee 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -[![SRG Media Player logo](README-images/logo.png)](https://github.com/SRGSSR/srgidentity-apple) +[![SRG Identity logo](README-images/logo.png)](https://github.com/SRGSSR/srgidentity-apple) [![GitHub releases](https://img.shields.io/github/v/release/SRGSSR/srgidentity-apple)](https://github.com/SRGSSR/srgidentity-apple/releases) [![platform](https://img.shields.io/badge/platfom-ios%20%7C%20tvos-blue)](https://github.com/SRGSSR/srgidentity-apple) [![Build Status](https://travis-ci.org/SRGSSR/srgidentity-apple.svg?branch=master)](https://travis-ci.org/SRGSSR/srgidentity-apple/branches) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![GitHub license](https://img.shields.io/github/license/SRGSSR/srgidentity-apple)](https://github.com/SRGSSR/srgidentity-apple/blob/master/LICENSE) From ea307d7dac5cbe742e9b14c8ccd9ea6bd196d4b2 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sat, 14 Dec 2019 18:50:35 +0100 Subject: [PATCH 44/55] Update dependencies --- Cartfile | 4 ++-- Cartfile.resolved | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cartfile b/Cartfile index bb149b7..348c5ed 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,5 @@ github "Mantle/Mantle" "2.1.0" github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" -github "SRGSSR/srgappearance-apple" "77bc6d887110e45957ac5320a2008a649efbf74c" -github "SRGSSR/srgnetwork-apple" "abe8363f55ba72837b2d93d124e6d6475806cfd1" +github "SRGSSR/srgappearance-apple" "285f8890d27f451f8b6375c8e4ca73ec3bc41a29" +github "SRGSSR/srgnetwork-apple" "e4f962720ee8ff9ecf099787aef6bcf3a7a9191b" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index b08b1c6..054b0d3 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -4,6 +4,6 @@ github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" -github "SRGSSR/srgappearance-apple" "77bc6d887110e45957ac5320a2008a649efbf74c" +github "SRGSSR/srgappearance-apple" "285f8890d27f451f8b6375c8e4ca73ec3bc41a29" github "SRGSSR/srglogger-apple" "40946ee91c53886c1b8c76f7d18be0880dfffb72" -github "SRGSSR/srgnetwork-apple" "abe8363f55ba72837b2d93d124e6d6475806cfd1" +github "SRGSSR/srgnetwork-apple" "e4f962720ee8ff9ecf099787aef6bcf3a7a9191b" From 732a266a5ef192677978cd97252cf2b1c428d549 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sat, 14 Dec 2019 18:51:18 +0100 Subject: [PATCH 45/55] Fastlane: enable tvOS tests --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 52a3db7..e317ebc 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -25,7 +25,7 @@ platform :ios do override_test_product_names - run_tests_with_devices(['iPhone 11']) + run_tests_with_devices(['iPhone 11', 'Apple TV']) trainer( path: './fastlane', From 9acd30bba0d8e8d9e2faae52a228ac266eca3191 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sat, 14 Dec 2019 19:34:57 +0100 Subject: [PATCH 46/55] Update documentation --- docs/GETTING_STARTED.md | 5 ++++- docs/README.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index dad4ef9..176815d 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -29,7 +29,10 @@ To allow for a user to login, call the `-loginWithEmailAddress:` instance method [SRGIdentityService.currentIdentityService loginWithEmailAddress:nil]; ``` -On iOS this presents a sandboxed Safari browser, in which the user can supply her credentials or open an account. On tvOS a dedicated in-app view is presented, with which currently users can only log in (a message invite them to open an account on a computer or mobile device). A user remains logged in until she logs out. +- On iOS this presents a sandboxed Safari browser, in which the user can supply her credentials or open an account. +- On tvOS a dedicated in-app view is presented, with which currently users can only log in (a message invite them to open an account on a computer or mobile device). + +A user remains logged in until she logs out. #### Remark diff --git a/docs/README.md b/docs/README.md index 0a6fdee..32c7b24 100644 --- a/docs/README.md +++ b/docs/README.md @@ -87,7 +87,7 @@ To learn about how the library can be used, have a look at the [getting started ### Logging -The library internally uses the [SRG Logger](https://github.com/SRGSSR/srglogger-apple) library for logging, within the `ch.srgssr.mediaplayer` subsystem. This logger either automatically integrates with your own logger, or can be easily integrated with it. Refer to the SRG Logger documentation for more information. +The library internally uses the [SRG Logger](https://github.com/SRGSSR/srglogger-apple) library for logging, within the `ch.srgssr.identity` subsystem. This logger either automatically integrates with your own logger, or can be easily integrated with it. Refer to the SRG Logger documentation for more information. ## License From 79b55a6e5c99149bb594d2c0f2f0b7efc950eaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Sat, 14 Dec 2019 19:57:05 +0100 Subject: [PATCH 47/55] Improve dark mode link readability --- .../SRGIdentityLoginViewController~tvos.m | 11 +++--- ...dentityLoginViewController~tvos.storyboard | 36 +++++++++++++------ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index 8f4bceb..a1ff941 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -25,6 +25,7 @@ @interface SRGIdentityLoginViewController () @property (nonatomic, weak) IBOutlet UIButton *loginButton; @property (nonatomic, weak) IBOutlet UILabel *instructionsLabel; +@property (nonatomic, weak) IBOutlet UILabel *linkLabel; @property (nonatomic, weak) SRGRequest *loginRequest; @@ -65,14 +66,12 @@ - (void)viewDidLoad self.loginButton.titleLabel.font = [UIFont srg_regularFontWithSize:36.f]; - NSMutableAttributedString *instructions = [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV (visit a website on another device)")]; - [instructions appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; - [instructions appendAttributedString:[[NSAttributedString alloc] initWithString:self.websiteURL.absoluteString - attributes:@{ NSForegroundColorAttributeName : UIColor.blueColor }]]; - - self.instructionsLabel.attributedText = instructions.copy; + self.instructionsLabel.text = NSLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV (visit a website on another device)"); self.instructionsLabel.font = [UIFont srg_regularFontWithSize:30.f]; + self.linkLabel.text = self.websiteURL.absoluteString; + self.linkLabel.font = [UIFont srg_regularFontWithSize:30.f]; + self.linkLabel.textColor = UIColor.systemBlueColor; } - (void)viewDidDisappear:(BOOL)animated diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index c76ff5e..317020b 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -1,9 +1,9 @@ - + - + @@ -65,27 +65,41 @@ - + - - + + + From 2d6aa36ce2ad10007a3837701b69dcefb358ba48 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sat, 14 Dec 2019 21:29:59 +0100 Subject: [PATCH 48/55] Prepare all framework strings for translation --- .../Login/SRGIdentityLoginViewController~tvos.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index a1ff941..acfeb9a 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -66,7 +66,7 @@ - (void)viewDidLoad self.loginButton.titleLabel.font = [UIFont srg_regularFontWithSize:36.f]; - self.instructionsLabel.text = NSLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV (visit a website on another device)"); + self.instructionsLabel.text = SRGIdentityLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device)"); self.instructionsLabel.font = [UIFont srg_regularFontWithSize:30.f]; self.linkLabel.text = self.websiteURL.absoluteString; @@ -145,7 +145,7 @@ - (IBAction)login:(id)sender UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") message:SRGIdentityLocalizedString(@"An email address is mandatory", @"Error description when no email address has been provided") preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [alertController addAction:[UIAlertAction actionWithTitle:SRGIdentityLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alertController animated:YES completion:nil]; return; } @@ -155,7 +155,7 @@ - (IBAction)login:(id)sender UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Incomplete information", @"Error title for incomplete login information") message:SRGIdentityLocalizedString(@"A password is mandatory", @"Error description when no password has been provided") preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [alertController addAction:[UIAlertAction actionWithTitle:SRGIdentityLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alertController animated:YES completion:nil]; return; } @@ -170,10 +170,10 @@ - (IBAction)login:(id)sender return; } - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error", "Title of a generic error alert") + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:SRGIdentityLocalizedString(@"Error", "Title of a generic error alert") message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; + [alertController addAction:[UIAlertAction actionWithTitle:SRGIdentityLocalizedString(@"Dismiss", @"Dismiss button label") style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alertController animated:YES completion:nil]; return; } From 8bcc183e21a6b3e9b091924686dbe920fa2e8811 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sun, 15 Dec 2019 00:33:30 +0100 Subject: [PATCH 49/55] Fix build phases --- SRGIdentity.xcodeproj/project.pbxproj | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 78dbe58..645f2f9 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -46,7 +46,6 @@ 6FB74D772101D5D600E2D365 /* IdentityServiceTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB74D742101D5D600E2D365 /* IdentityServiceTestCase.m */; }; 6FC7C5A323A3A13E0058349C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FC7C5A223A3A13E0058349C /* Images.xcassets */; }; 6FC7C5A523A3A6D80058349C /* SRGAppearance.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FC7C5A423A3A6D70058349C /* SRGAppearance.framework */; }; - 6FC7C5A623A3A6D80058349C /* SRGAppearance.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6FC7C5A423A3A6D70058349C /* SRGAppearance.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6FCBBD57221D8E95003CE752 /* SRGIdentityWebViewController~ios.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF846A1221BED95006FC3FC /* SRGIdentityWebViewController~ios.storyboard */; }; 6FCBBD5A221DB644003CE752 /* SRGIdentityNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCBBD58221DB644003CE752 /* SRGIdentityNavigationController.h */; }; 6FCBBD5B221DB644003CE752 /* SRGIdentityNavigationController~ios.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCBBD59221DB644003CE752 /* SRGIdentityNavigationController~ios.m */; }; @@ -99,17 +98,6 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - 6FC7C5A723A3A6D80058349C /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 6FC7C5A623A3A6D80058349C /* SRGAppearance.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -519,7 +507,6 @@ 6F0EB52D20FC7F58009C02CF /* Frameworks */, 6F0EB52E20FC7F58009C02CF /* Headers */, 6F0EB52F20FC7F58009C02CF /* Resources */, - 6FC7C5A723A3A6D80058349C /* Embed Frameworks */, ); buildRules = ( ); From 7e5dc8178e26c7c4be625382fafa2164e72fe781 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sun, 15 Dec 2019 01:52:34 +0100 Subject: [PATCH 50/55] Missing translation key --- .../Sources/Login/SRGIdentityLoginViewController~tvos.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index acfeb9a..b3a79e7 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -58,12 +58,13 @@ - (void)viewDidLoad [super viewDidLoad]; self.emailAddressTextField.text = self.emailAddress; - self.emailAddressTextField.placeholder = SRGIdentityLocalizedString(@"Email address", @"Email address text field placeholder"); + self.emailAddressTextField.placeholder = SRGIdentityLocalizedString(@"Email address", @"Email address text field placeholder on Apple TV"); self.emailAddressTextField.font = [UIFont srg_regularFontWithSize:42.f]; - self.passwordTextField.placeholder = SRGIdentityLocalizedString(@"Password", @"Password text field placeholder"); + self.passwordTextField.placeholder = SRGIdentityLocalizedString(@"Password", @"Password text field placeholder on Apple TV"); self.passwordTextField.font = [UIFont srg_regularFontWithSize:42.f]; + [self.loginButton setTitle:SRGIdentityLocalizedString(@"Sign in", @"Sign in button on Apple TV") forState:UIControlStateNormal]; self.loginButton.titleLabel.font = [UIFont srg_regularFontWithSize:36.f]; self.instructionsLabel.text = SRGIdentityLocalizedString(@"To sign up or manage your account, use a computer or mobile device and visit", @"Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device)"); From d10c201551077ac147823bb13775fdeed5650518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Sun, 15 Dec 2019 10:03:26 +0100 Subject: [PATCH 51/55] Update French translations --- .../Resources/de.lproj/Localizable.strings | 30 +++++++++++++++++++ .../Resources/en.lproj/Localizable.strings | 30 +++++++++++++++++++ .../Resources/fr.lproj/Localizable.strings | 30 +++++++++++++++++++ .../Resources/it.lproj/Localizable.strings | 30 +++++++++++++++++++ .../Resources/rm.lproj/Localizable.strings | 30 +++++++++++++++++++ 5 files changed, 150 insertions(+) diff --git a/Framework/Resources/de.lproj/Localizable.strings b/Framework/Resources/de.lproj/Localizable.strings index cb63ce9..5d5c264 100644 --- a/Framework/Resources/de.lproj/Localizable.strings +++ b/Framework/Resources/de.lproj/Localizable.strings @@ -1,5 +1,35 @@ +/* Error description when no password has been provided */ +"A password is mandatory" = "A password is mandatory"; + +/* Error description when no email address has been provided */ +"An email address is mandatory" = "An email address is mandatory"; + /* Close button title */ "Close" = "Schliessen"; +/* Dismiss button label */ +"Dismiss" = "Dismiss"; + +/* Email address text field placeholder on Apple TV */ +"Email address" = "Email address"; + +/* Title of a generic error alert */ +"Error" = "Error"; + +/* Error title for incomplete login information */ +"Incomplete information" = "Incomplete information"; + /* Title displayed at the top of the account view */ "My account" = "Mein Konto"; + +/* Password text field placeholder on Apple TV */ +"Password" = "Password"; + +/* Sign in button on Apple TV */ +"Sign in" = "Sign in"; + +/* Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device) */ +"To sign up or manage your account, use a computer or mobile device and visit" = "To sign up or manage your account, use a computer or mobile device and visit"; + +/* Error message displayed when incorrect user credentials have been supplied */ +"Wrong email address or password" = "Wrong email address or password"; diff --git a/Framework/Resources/en.lproj/Localizable.strings b/Framework/Resources/en.lproj/Localizable.strings index 084a703..d8e4263 100644 --- a/Framework/Resources/en.lproj/Localizable.strings +++ b/Framework/Resources/en.lproj/Localizable.strings @@ -1,5 +1,35 @@ +/* Error description when no password has been provided */ +"A password is mandatory" = "A password is mandatory"; + +/* Error description when no email address has been provided */ +"An email address is mandatory" = "An email address is mandatory"; + /* Close button title */ "Close" = "Close"; +/* Dismiss button label */ +"Dismiss" = "Dismiss"; + +/* Email address text field placeholder on Apple TV */ +"Email address" = "Email address"; + +/* Title of a generic error alert */ +"Error" = "Error"; + +/* Error title for incomplete login information */ +"Incomplete information" = "Incomplete information"; + /* Title displayed at the top of the account view */ "My account" = "My account"; + +/* Password text field placeholder on Apple TV */ +"Password" = "Password"; + +/* Sign in button on Apple TV */ +"Sign in" = "Sign in"; + +/* Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device) */ +"To sign up or manage your account, use a computer or mobile device and visit" = "To sign up or manage your account, use a computer or mobile device and visit"; + +/* Error message displayed when incorrect user credentials have been supplied */ +"Wrong email address or password" = "Wrong email address or password"; diff --git a/Framework/Resources/fr.lproj/Localizable.strings b/Framework/Resources/fr.lproj/Localizable.strings index d80c841..9117f5a 100644 --- a/Framework/Resources/fr.lproj/Localizable.strings +++ b/Framework/Resources/fr.lproj/Localizable.strings @@ -1,5 +1,35 @@ +/* Error description when no password has been provided */ +"A password is mandatory" = "Veuillez saisir un mot de passe"; + +/* Error description when no email address has been provided */ +"An email address is mandatory" = "Veuillez saisir une adresse e-mail"; + /* Close button title */ "Close" = "Fermer"; +/* Dismiss button label */ +"Dismiss" = "Fermer"; + +/* Email address text field placeholder on Apple TV */ +"Email address" = "Adresse e-mail"; + +/* Title of a generic error alert */ +"Error" = "Erreur"; + +/* Error title for incomplete login information */ +"Incomplete information" = "Informations incomplètes"; + /* Title displayed at the top of the account view */ "My account" = "Mon profil"; + +/* Password text field placeholder on Apple TV */ +"Password" = "Mot de passe"; + +/* Sign in button on Apple TV */ +"Sign in" = "Se connecter"; + +/* Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device) */ +"To sign up or manage your account, use a computer or mobile device and visit" = "Pour ouvrir un nouveau compte ou gérer un compte existant, utilisez un ordinateur ou un appareil mobile et visitez"; + +/* Error message displayed when incorrect user credentials have been supplied */ +"Wrong email address or password" = "Adresse e-mail et / ou mot de passe incorrects"; diff --git a/Framework/Resources/it.lproj/Localizable.strings b/Framework/Resources/it.lproj/Localizable.strings index a01d85a..b967348 100644 --- a/Framework/Resources/it.lproj/Localizable.strings +++ b/Framework/Resources/it.lproj/Localizable.strings @@ -1,5 +1,35 @@ +/* Error description when no password has been provided */ +"A password is mandatory" = "A password is mandatory"; + +/* Error description when no email address has been provided */ +"An email address is mandatory" = "An email address is mandatory"; + /* Close button title */ "Close" = "Chiudi"; +/* Dismiss button label */ +"Dismiss" = "Dismiss"; + +/* Email address text field placeholder on Apple TV */ +"Email address" = "Email address"; + +/* Title of a generic error alert */ +"Error" = "Error"; + +/* Error title for incomplete login information */ +"Incomplete information" = "Incomplete information"; + /* Title displayed at the top of the account view */ "My account" = "Il mio account"; + +/* Password text field placeholder on Apple TV */ +"Password" = "Password"; + +/* Sign in button on Apple TV */ +"Sign in" = "Sign in"; + +/* Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device) */ +"To sign up or manage your account, use a computer or mobile device and visit" = "To sign up or manage your account, use a computer or mobile device and visit"; + +/* Error message displayed when incorrect user credentials have been supplied */ +"Wrong email address or password" = "Wrong email address or password"; diff --git a/Framework/Resources/rm.lproj/Localizable.strings b/Framework/Resources/rm.lproj/Localizable.strings index 06dd9a1..104e577 100644 --- a/Framework/Resources/rm.lproj/Localizable.strings +++ b/Framework/Resources/rm.lproj/Localizable.strings @@ -1,5 +1,35 @@ +/* Error description when no password has been provided */ +"A password is mandatory" = "A password is mandatory"; + +/* Error description when no email address has been provided */ +"An email address is mandatory" = "An email address is mandatory"; + /* Close button title */ "Close" = "Serrar"; +/* Dismiss button label */ +"Dismiss" = "Dismiss"; + +/* Email address text field placeholder on Apple TV */ +"Email address" = "Email address"; + +/* Title of a generic error alert */ +"Error" = "Error"; + +/* Error title for incomplete login information */ +"Incomplete information" = "Incomplete information"; + /* Title displayed at the top of the account view */ "My account" = "Mes conto"; + +/* Password text field placeholder on Apple TV */ +"Password" = "Password"; + +/* Sign in button on Apple TV */ +"Sign in" = "Sign in"; + +/* Instructions for signup on Apple TV followed by a website url (i.e. visit a website on another device) */ +"To sign up or manage your account, use a computer or mobile device and visit" = "To sign up or manage your account, use a computer or mobile device and visit"; + +/* Error message displayed when incorrect user credentials have been supplied */ +"Wrong email address or password" = "Wrong email address or password"; From 41c2d864912a0a657deb68d96c0af1910d8eafd4 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Sat, 14 Dec 2019 21:04:27 +0100 Subject: [PATCH 52/55] Default service logo, and hidden image override --- .../Contents.json | 0 .../identity_service_logo.imageset}/marts.pdf | Bin .../service_logo.imageset/Contents.json | 15 ++++++++++++ .../identity_service_logo.pdf | Bin 0 -> 6197 bytes .../Sources/Categories/UIImage+SRGIdentity.h | 23 ++++++++++++++++++ .../Sources/Categories/UIImage+SRGIdentity.m | 18 ++++++++++++++ .../SRGIdentityLoginViewController~tvos.m | 5 ++++ ...dentityLoginViewController~tvos.storyboard | 9 ++++--- SRGIdentity.xcodeproj/project.pbxproj | 12 +++++++-- 9 files changed, 76 insertions(+), 6 deletions(-) rename {Framework/Resources/Images.xcassets/marts.imageset => Demo/Resources/Images.xcassets/identity_service_logo.imageset}/Contents.json (100%) rename {Framework/Resources/Images.xcassets/marts.imageset => Demo/Resources/Images.xcassets/identity_service_logo.imageset}/marts.pdf (100%) create mode 100644 Framework/Resources/Images.xcassets/service_logo.imageset/Contents.json create mode 100644 Framework/Resources/Images.xcassets/service_logo.imageset/identity_service_logo.pdf create mode 100644 Framework/Sources/Categories/UIImage+SRGIdentity.h create mode 100644 Framework/Sources/Categories/UIImage+SRGIdentity.m diff --git a/Framework/Resources/Images.xcassets/marts.imageset/Contents.json b/Demo/Resources/Images.xcassets/identity_service_logo.imageset/Contents.json similarity index 100% rename from Framework/Resources/Images.xcassets/marts.imageset/Contents.json rename to Demo/Resources/Images.xcassets/identity_service_logo.imageset/Contents.json diff --git a/Framework/Resources/Images.xcassets/marts.imageset/marts.pdf b/Demo/Resources/Images.xcassets/identity_service_logo.imageset/marts.pdf similarity index 100% rename from Framework/Resources/Images.xcassets/marts.imageset/marts.pdf rename to Demo/Resources/Images.xcassets/identity_service_logo.imageset/marts.pdf diff --git a/Framework/Resources/Images.xcassets/service_logo.imageset/Contents.json b/Framework/Resources/Images.xcassets/service_logo.imageset/Contents.json new file mode 100644 index 0000000..b80857d --- /dev/null +++ b/Framework/Resources/Images.xcassets/service_logo.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "identity_service_logo.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Framework/Resources/Images.xcassets/service_logo.imageset/identity_service_logo.pdf b/Framework/Resources/Images.xcassets/service_logo.imageset/identity_service_logo.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2bbaab7ac3871bf415234f9b03a894c9f916078b GIT binary patch literal 6197 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 literal 0 HcmV?d00001 diff --git a/Framework/Sources/Categories/UIImage+SRGIdentity.h b/Framework/Sources/Categories/UIImage+SRGIdentity.h new file mode 100644 index 0000000..062d570 --- /dev/null +++ b/Framework/Sources/Categories/UIImage+SRGIdentity.h @@ -0,0 +1,23 @@ +// +// Copyright (c) SRG SSR. All rights reserved. +// +// License information is available from the LICENSE file. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Standard images from Identity bundle. + */ +@interface UIImage (SRGIdentityImages) + +/** + * Return the specified image from the Identity bundle, `nil` if not found. + */ ++ (nullable UIImage *)srg_identityImageNamed:(NSString *)imageName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Framework/Sources/Categories/UIImage+SRGIdentity.m b/Framework/Sources/Categories/UIImage+SRGIdentity.m new file mode 100644 index 0000000..175ca79 --- /dev/null +++ b/Framework/Sources/Categories/UIImage+SRGIdentity.m @@ -0,0 +1,18 @@ +// +// Copyright (c) SRG SSR. All rights reserved. +// +// License information is available from the LICENSE file. +// + +#import "UIImage+SRGIdentity.h" + +#import "NSBundle+SRGIdentity.h" + +@implementation UIImage (SRGIdentityImages) + ++ (UIImage *)srg_identityImageNamed:(NSString *)imageName +{ + return [UIImage imageNamed:imageName inBundle:NSBundle.srg_identityBundle compatibleWithTraitCollection:nil]; +} + +@end diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m index b3a79e7..ce9f575 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.m @@ -7,6 +7,7 @@ #import "SRGIdentityLoginViewController.h" #import "NSBundle+SRGIdentity.h" +#import "UIImage+SRGIdentity.h" #import #import @@ -20,6 +21,7 @@ @interface SRGIdentityLoginViewController () @property (nonatomic, copy) void (^tokenBlock)(NSString *sessionToken); @property (nonatomic, copy) void (^dismissalBlock)(void); +@property (nonatomic, weak) IBOutlet UIImageView *serviceLogoImageView; @property (nonatomic, weak) IBOutlet UITextField *emailAddressTextField; @property (nonatomic, weak) IBOutlet UITextField *passwordTextField; @property (nonatomic, weak) IBOutlet UIButton *loginButton; @@ -57,6 +59,9 @@ - (void)viewDidLoad { [super viewDidLoad]; + self.serviceLogoImageView.image = [UIImage imageNamed:@"identity_service_logo"] ?: [UIImage srg_identityImageNamed:@"service_logo"]; + self.serviceLogoImageView.tintColor = UIColor.systemGrayColor; + self.emailAddressTextField.text = self.emailAddress; self.emailAddressTextField.placeholder = SRGIdentityLocalizedString(@"Email address", @"Email address text field placeholder on Apple TV"); self.emailAddressTextField.font = [UIFont srg_regularFontWithSize:42.f]; diff --git a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard index 317020b..ae4b372 100644 --- a/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard +++ b/Framework/Sources/Login/SRGIdentityLoginViewController~tvos.storyboard @@ -1,9 +1,9 @@ - + - + @@ -23,7 +23,7 @@ - + @@ -102,6 +102,7 @@ + @@ -110,6 +111,6 @@ - + diff --git a/SRGIdentity.xcodeproj/project.pbxproj b/SRGIdentity.xcodeproj/project.pbxproj index 645f2f9..bfae2f2 100644 --- a/SRGIdentity.xcodeproj/project.pbxproj +++ b/SRGIdentity.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 0829FA812136853C00FE0A28 /* NSBundle+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0829FA7B2136853C00FE0A28 /* NSBundle+SRGIdentity.m */; }; 084CD6FF21696C0A00905A38 /* SRGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084CD6FE21696C0A00905A38 /* SRGLogger.framework */; }; 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 086BB713216967220079483E /* SRGIdentityLogger.h */; }; + 0875854A23A573FC00FA7207 /* UIImage+SRGIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 0875854823A573FC00FA7207 /* UIImage+SRGIdentity.h */; }; + 0875854B23A573FC00FA7207 /* UIImage+SRGIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0875854923A573FC00FA7207 /* UIImage+SRGIdentity.m */; }; 6F0C98F12121E26A00073AB6 /* SRGIdentity.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6F0C98E62121E1C200073AB6 /* SRGIdentity.bundle */; }; 6F19DA7F221DF6E100085C7D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F19DA7D221DF6E100085C7D /* Localizable.strings */; }; 6F55003C237BCB02003476E2 /* DemosViewController~tvos.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6F55003B237BCB02003476E2 /* DemosViewController~tvos.storyboard */; }; @@ -123,6 +125,8 @@ 086BB713216967220079483E /* SRGIdentityLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRGIdentityLogger.h; sourceTree = ""; }; 086FB2CA21368ADE00DE4CF2 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 086FB33521380D9300DE4CF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0875854823A573FC00FA7207 /* UIImage+SRGIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+SRGIdentity.h"; sourceTree = ""; }; + 0875854923A573FC00FA7207 /* UIImage+SRGIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+SRGIdentity.m"; sourceTree = ""; }; 0895B2E023368DF7009922C6 /* TestApp.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TestApp.xcconfig; sourceTree = ""; }; 6F0402F22331318700DA4D97 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; 6F0402F3233131A000DA4D97 /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; @@ -242,10 +246,12 @@ 0829FA792136853C00FE0A28 /* Categories */ = { isa = PBXGroup; children = ( - 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */, - 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */, 0829FA7A2136853C00FE0A28 /* NSBundle+SRGIdentity.h */, 0829FA7B2136853C00FE0A28 /* NSBundle+SRGIdentity.m */, + 0875854823A573FC00FA7207 /* UIImage+SRGIdentity.h */, + 0875854923A573FC00FA7207 /* UIImage+SRGIdentity.m */, + 6F979F3121F72A18002A2495 /* UIWindow+SRGIdentity.h */, + 6F979F3021F72A18002A2495 /* UIWindow+SRGIdentity.m */, ); path = Categories; sourceTree = ""; @@ -456,6 +462,7 @@ 0829FA802136853C00FE0A28 /* NSBundle+SRGIdentity.h in Headers */, 6F979F3321F72A18002A2495 /* UIWindow+SRGIdentity.h in Headers */, 6F9A1FDC23A27153002ECFC8 /* SRGIdentityLoginViewController.h in Headers */, + 0875854A23A573FC00FA7207 /* UIImage+SRGIdentity.h in Headers */, 0829FA7E2136853C00FE0A28 /* SRGIdentity.h in Headers */, 080D0BD8213566C900AA519A /* SRGIdentityService.h in Headers */, 086BB714216967220079483E /* SRGIdentityLogger.h in Headers */, @@ -711,6 +718,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0875854B23A573FC00FA7207 /* UIImage+SRGIdentity.m in Sources */, 6FF846A9221BF93F006FC3FC /* SRGIdentityModalTransition~ios.m in Sources */, 6F9A1FDD23A27153002ECFC8 /* SRGIdentityLoginViewController~tvos.m in Sources */, 080D0BD7213566C900AA519A /* SRGIdentityService.m in Sources */, From 74a7db60cf3353022a886717346d6806ce540b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Mon, 16 Dec 2019 10:37:27 +0100 Subject: [PATCH 53/55] Document logo override mechanism --- Framework/Sources/SRGIdentityService.h | 5 +++++ docs/GETTING_STARTED.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Framework/Sources/SRGIdentityService.h b/Framework/Sources/SRGIdentityService.h index 38d6d25..21236dc 100644 --- a/Framework/Sources/SRGIdentityService.h +++ b/Framework/Sources/SRGIdentityService.h @@ -109,6 +109,11 @@ OBJC_EXPORT NSString * const SRGIdentityServiceDeletedKey; // Key t * * @return `YES` if the form could be opened. The method might return `NO` if another attempt is already being made * or if a user is already logged in. + * + * @discussion - On iOS this presents a browser, in which the user can supply her credentials or open an account. + * - On tvOS a dedicated in-app view is presented, with which users can only log in (a message invite them + * to open an account on a computer or mobile device). You can customize the logo displayed on this view + * by adding an `identity_service_logo` image file to your project (with recommended size of 150x150 px). */ - (BOOL)loginWithEmailAddress:(nullable NSString *)emailAddress; diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 176815d..a63f3c5 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -29,8 +29,8 @@ To allow for a user to login, call the `-loginWithEmailAddress:` instance method [SRGIdentityService.currentIdentityService loginWithEmailAddress:nil]; ``` -- On iOS this presents a sandboxed Safari browser, in which the user can supply her credentials or open an account. -- On tvOS a dedicated in-app view is presented, with which currently users can only log in (a message invite them to open an account on a computer or mobile device). +- On iOS this presents a browser, in which the user can supply her credentials or open an account. +- On tvOS a dedicated in-app view is presented, with which users can only log in (a message invite them to open an account on a computer or mobile device). You can customize the logo displayed on this view by adding an `identity_service_logo` image file to your project (with recommended size of 150x150 px). A user remains logged in until she logs out. From 7a27a9726376e654ef119a6f1d9e4c22aa13868f Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Tue, 17 Dec 2019 16:26:51 +0100 Subject: [PATCH 54/55] Update Fastlane --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 60e9d99..f29951a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,7 +12,7 @@ GIT GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.1) + CFPropertyList (3.0.2) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) atomos (0.1.3) @@ -29,8 +29,8 @@ GEM unf (>= 0.0.5, < 1.0.0) dotenv (2.7.5) emoji_regex (1.0.1) - excon (0.68.0) - faraday (0.17.0) + excon (0.71.0) + faraday (0.17.1) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) faraday (>= 0.7.4) @@ -38,7 +38,7 @@ GEM faraday_middleware (0.13.1) faraday (>= 0.7.4, < 1.0) fastimage (2.1.7) - fastlane (2.134.0) + fastlane (2.137.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) @@ -105,9 +105,9 @@ GEM http-cookie (1.0.3) domain_name (~> 0.5) httpclient (2.8.3) - json (2.2.0) + json (2.3.0) jwt (2.1.0) - memoist (0.16.1) + memoist (0.16.2) mime-types (3.3) mime-types-data (~> 3.2015) mime-types-data (3.2019.1009) @@ -142,7 +142,7 @@ GEM unicode-display_width (~> 1.1, >= 1.1.1) tty-cursor (0.7.0) tty-screen (0.7.0) - tty-spinner (0.9.1) + tty-spinner (0.9.2) tty-cursor (~> 0.7) uber (0.1.0) unf (0.1.4) @@ -150,7 +150,7 @@ GEM unf_ext (0.0.7.6) unicode-display_width (1.6.0) word_wrap (1.0.0) - xcodeproj (1.13.0) + xcodeproj (1.14.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) From c652c457d6816af9293f21002b87d89283529197 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Tue, 17 Dec 2019 16:34:29 +0100 Subject: [PATCH 55/55] Update dependencies --- Cartfile | 6 +++--- Cartfile.resolved | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cartfile b/Cartfile index 348c5ed..d815c52 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,5 @@ github "Mantle/Mantle" "2.1.0" -github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" -github "SRGSSR/srgappearance-apple" "285f8890d27f451f8b6375c8e4ca73ec3bc41a29" -github "SRGSSR/srgnetwork-apple" "e4f962720ee8ff9ecf099787aef6bcf3a7a9191b" +github "SRGSSR/FXReachability" "1.3.2_srg4" +github "SRGSSR/srgappearance-apple" "2.0.0" +github "SRGSSR/srgnetwork-apple" "2.0.0" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 054b0d3..004de2b 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,9 +1,9 @@ github "AliSoftware/OHHTTPStubs" "8.0.0" github "Mantle/Mantle" "2.1.0" -github "SRGSSR/FXReachability" "f20cd62474d5707d4ca04513473516ba6cdd6c80" -github "SRGSSR/MAKVONotificationCenter" "acf9ce3d6a33592480da2a581dcdc30ed647deac" +github "SRGSSR/FXReachability" "1.3.2_srg4" +github "SRGSSR/MAKVONotificationCenter" "1.0_srg4" github "SRGSSR/UICKeyChainStore" "v2.1.2_srg1" -github "SRGSSR/libextobjc" "33fa3553081acde18089f594051a25710180f679" -github "SRGSSR/srgappearance-apple" "285f8890d27f451f8b6375c8e4ca73ec3bc41a29" -github "SRGSSR/srglogger-apple" "40946ee91c53886c1b8c76f7d18be0880dfffb72" -github "SRGSSR/srgnetwork-apple" "e4f962720ee8ff9ecf099787aef6bcf3a7a9191b" +github "SRGSSR/libextobjc" "0.6_srg2" +github "SRGSSR/srgappearance-apple" "2.0.0" +github "SRGSSR/srglogger-apple" "2.0.0" +github "SRGSSR/srgnetwork-apple" "2.0.0"