From 42bc113754d2f9e2f0f6cf552916ae76149e717d Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 9 Apr 2018 09:11:21 -0700 Subject: Travis static library testing (#1047) * Add Objective C example app for Messaging * Travis static library testing * static lib build fixes --- Example/Firebase.xcodeproj/project.pbxproj | 316 +++++++++++++++----- .../xcschemes/Messaging_Sample_iOS.xcscheme | 91 ++++++ Example/Messaging/App/GoogleService-Info.plist | 28 -- Example/Messaging/App/iOS/AppDelegate.swift | 153 ---------- .../App/iOS/Base.lproj/LaunchScreen.storyboard | 12 +- .../Messaging/App/iOS/Base.lproj/Main.storyboard | 47 +-- .../App/iOS/Data+MessagingExtensions.swift | 25 -- Example/Messaging/App/iOS/Environment.swift | 28 -- Example/Messaging/App/iOS/FIRAppDelegate.h | 23 ++ Example/Messaging/App/iOS/FIRAppDelegate.m | 58 ++++ Example/Messaging/App/iOS/FIRViewController.h | 21 ++ Example/Messaging/App/iOS/FIRViewController.m | 33 ++ Example/Messaging/App/iOS/Messaging-Info.plist | 55 ---- .../App/iOS/MessagingViewController.swift | 332 --------------------- .../App/iOS/Messaging_Example.entitlements | 8 - .../App/iOS/NotificationsController.swift | 141 --------- Example/Messaging/App/iOS/main.m | 22 ++ Example/Messaging/Sample/GoogleService-Info.plist | 28 ++ Example/Messaging/Sample/iOS/AppDelegate.swift | 153 ++++++++++ .../Sample/iOS/Base.lproj/LaunchScreen.storyboard | 27 ++ .../Sample/iOS/Base.lproj/Main.storyboard | 48 +++ .../Sample/iOS/Data+MessagingExtensions.swift | 25 ++ Example/Messaging/Sample/iOS/Environment.swift | 28 ++ Example/Messaging/Sample/iOS/Messaging-Info.plist | 55 ++++ .../Sample/iOS/MessagingViewController.swift | 332 +++++++++++++++++++++ .../Sample/iOS/Messaging_Example.entitlements | 8 + .../Sample/iOS/NotificationsController.swift | 141 +++++++++ Example/Podfile | 6 +- Example/Storage/App/iOS/FIRAppDelegate.m | 2 - 29 files changed, 1356 insertions(+), 890 deletions(-) create mode 100644 Example/Firebase.xcodeproj/xcshareddata/xcschemes/Messaging_Sample_iOS.xcscheme delete mode 100644 Example/Messaging/App/GoogleService-Info.plist delete mode 100644 Example/Messaging/App/iOS/AppDelegate.swift delete mode 100644 Example/Messaging/App/iOS/Data+MessagingExtensions.swift delete mode 100644 Example/Messaging/App/iOS/Environment.swift create mode 100644 Example/Messaging/App/iOS/FIRAppDelegate.h create mode 100644 Example/Messaging/App/iOS/FIRAppDelegate.m create mode 100644 Example/Messaging/App/iOS/FIRViewController.h create mode 100644 Example/Messaging/App/iOS/FIRViewController.m delete mode 100644 Example/Messaging/App/iOS/Messaging-Info.plist delete mode 100644 Example/Messaging/App/iOS/MessagingViewController.swift delete mode 100644 Example/Messaging/App/iOS/Messaging_Example.entitlements delete mode 100644 Example/Messaging/App/iOS/NotificationsController.swift create mode 100644 Example/Messaging/App/iOS/main.m create mode 100644 Example/Messaging/Sample/GoogleService-Info.plist create mode 100644 Example/Messaging/Sample/iOS/AppDelegate.swift create mode 100644 Example/Messaging/Sample/iOS/Base.lproj/LaunchScreen.storyboard create mode 100644 Example/Messaging/Sample/iOS/Base.lproj/Main.storyboard create mode 100644 Example/Messaging/Sample/iOS/Data+MessagingExtensions.swift create mode 100644 Example/Messaging/Sample/iOS/Environment.swift create mode 100644 Example/Messaging/Sample/iOS/Messaging-Info.plist create mode 100644 Example/Messaging/Sample/iOS/MessagingViewController.swift create mode 100644 Example/Messaging/Sample/iOS/Messaging_Example.entitlements create mode 100644 Example/Messaging/Sample/iOS/NotificationsController.swift (limited to 'Example') diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj index 315e02a..9fa954c 100644 --- a/Example/Firebase.xcodeproj/project.pbxproj +++ b/Example/Firebase.xcodeproj/project.pbxproj @@ -130,15 +130,6 @@ AFAF36F71EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; AFAF36F81EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; AFAF36F91EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; - AFC8BA9D1EBD230E00B8EEAE /* NotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFC8BA9C1EBD230E00B8EEAE /* NotificationsController.swift */; }; - AFC8BA9F1EBD51A700B8EEAE /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFC8BA9E1EBD51A700B8EEAE /* Environment.swift */; }; - AFC8BAA71EC257D800B8EEAE /* FIRSampleAppUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = AFC8BAA31EC257D800B8EEAE /* FIRSampleAppUtilities.m */; }; - AFD5630E1EB1402300EA2233 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD562FF1EB13DF200EA2233 /* AppDelegate.swift */; }; - AFD5630F1EB1402300EA2233 /* MessagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD563011EB13DF200EA2233 /* MessagingViewController.swift */; }; - AFD563151EB29EDE00EA2233 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = AFD563131EB1466100EA2233 /* GoogleService-Info.plist */; }; - AFD563171EBBEF7B00EA2233 /* Data+MessagingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD563161EBBEF7B00EA2233 /* Data+MessagingExtensions.swift */; }; - D018534D1EDACED4003A645C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D01853491EDACED4003A645C /* LaunchScreen.storyboard */; }; - D018534E1EDACED4003A645C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D018534B1EDACED4003A645C /* Main.storyboard */; }; D01853721EDAD084003A645C /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; D01853831EDAD113003A645C /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D018537E1EDAD0E6003A645C /* FIRAppDelegate.m */; }; D01853841EDAD113003A645C /* FIRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D01853801EDAD0E6003A645C /* FIRViewController.m */; }; @@ -332,6 +323,22 @@ DE26D2931F705F4D004AE1D3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE26D2071F70333E004AE1D3 /* ViewController.swift */; }; DE26D2941F705F51004AE1D3 /* AuthCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1FE1F70333E004AE1D3 /* AuthCredentials.swift */; }; DE26D2951F705F53004AE1D3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1FD1F70333E004AE1D3 /* AppDelegate.swift */; }; + DE47C0E2207AC87D00B1AEDF /* FIRSampleAppUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = AFC8BAA31EC257D800B8EEAE /* FIRSampleAppUtilities.m */; }; + DE47C0E7207AC87D00B1AEDF /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; + DE47C114207AC94A00B1AEDF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DE47C107207AC94A00B1AEDF /* GoogleService-Info.plist */; }; + DE47C115207AC94A00B1AEDF /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE47C109207AC94A00B1AEDF /* Environment.swift */; }; + DE47C116207AC94A00B1AEDF /* MessagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE47C10A207AC94A00B1AEDF /* MessagingViewController.swift */; }; + DE47C117207AC94A00B1AEDF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE47C10C207AC94A00B1AEDF /* LaunchScreen.storyboard */; }; + DE47C118207AC94A00B1AEDF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE47C10E207AC94A00B1AEDF /* Main.storyboard */; }; + DE47C119207AC94A00B1AEDF /* Messaging-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DE47C110207AC94A00B1AEDF /* Messaging-Info.plist */; }; + DE47C11A207AC94A00B1AEDF /* Data+MessagingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE47C111207AC94A00B1AEDF /* Data+MessagingExtensions.swift */; }; + DE47C11B207AC94A00B1AEDF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE47C112207AC94A00B1AEDF /* AppDelegate.swift */; }; + DE47C11C207AC94A00B1AEDF /* NotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE47C113207AC94A00B1AEDF /* NotificationsController.swift */; }; + DE47C13F207ACAA900B1AEDF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE47C136207ACAA900B1AEDF /* LaunchScreen.storyboard */; }; + DE47C140207ACAA900B1AEDF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE47C138207ACAA900B1AEDF /* Main.storyboard */; }; + DE47C142207ACAA900B1AEDF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DE47C13B207ACAA900B1AEDF /* main.m */; }; + DE47C143207ACAA900B1AEDF /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DE47C13C207ACAA900B1AEDF /* FIRAppDelegate.m */; }; + DE47C144207ACAA900B1AEDF /* FIRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE47C13D207ACAA900B1AEDF /* FIRViewController.m */; }; DE750DBD1EB3DD5B00A75E47 /* FIRAuthAPNSTokenTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE750DB61EB3DD4000A75E47 /* FIRAuthAPNSTokenTests.m */; }; DE750DBE1EB3DD6800A75E47 /* FIRAuthAPNSTokenManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE750DB51EB3DD4000A75E47 /* FIRAuthAPNSTokenManagerTests.m */; }; DE750DBF1EB3DD6C00A75E47 /* FIRAuthAppCredentialManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE750DB71EB3DD4000A75E47 /* FIRAuthAppCredentialManagerTests.m */; }; @@ -451,6 +458,7 @@ DE9316031E8738E60083EDBF /* FIRMessagingSyncMessageManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315D41E8738B70083EDBF /* FIRMessagingSyncMessageManagerTest.m */; }; DE9316041E8738E60083EDBF /* FIRMessagingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315D51E8738B70083EDBF /* FIRMessagingTest.m */; }; DE9316051E8738E60083EDBF /* FIRMessagingTestNotificationUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315D71E8738B70083EDBF /* FIRMessagingTestNotificationUtilities.m */; }; + DEA7795D207ACC8000245121 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DE47C107207AC94A00B1AEDF /* GoogleService-Info.plist */; }; DEAAD3C31FBA1CD90053BF48 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD3BD1FBA1CD80053BF48 /* main.m */; }; DEAAD3CE1FBA1EFA0053BF48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DEAAD3C51FBA1EF90053BF48 /* Assets.xcassets */; }; DEAAD3CF1FBA1EFA0053BF48 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD3C81FBA1EFA0053BF48 /* AppDelegate.m */; }; @@ -905,20 +913,10 @@ 923F824D206C4D8B00034974 /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/SafariServices.framework; sourceTree = DEVELOPER_DIR; }; 923F8250206C4DC500034974 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; }; AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Shared.xcassets; path = Shared/Shared.xcassets; sourceTree = ""; }; - AFC8BA9C1EBD230E00B8EEAE /* NotificationsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = ""; }; - AFC8BA9E1EBD51A700B8EEAE /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; AFC8BAA11EC257D700B8EEAE /* Messaging_Example-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Messaging_Example-Bridging-Header.h"; sourceTree = ""; }; AFC8BAA21EC257D800B8EEAE /* FIRSampleAppUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FIRSampleAppUtilities.h; path = Shared/FIRSampleAppUtilities.h; sourceTree = ""; }; AFC8BAA31EC257D800B8EEAE /* FIRSampleAppUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FIRSampleAppUtilities.m; path = Shared/FIRSampleAppUtilities.m; sourceTree = ""; }; AFD562E51EB13C6D00EA2233 /* Messaging_Example_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Messaging_Example_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; - AFD562FF1EB13DF200EA2233 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - AFD563001EB13DF200EA2233 /* Messaging-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Messaging-Info.plist"; sourceTree = ""; }; - AFD563011EB13DF200EA2233 /* MessagingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagingViewController.swift; sourceTree = ""; }; - AFD563131EB1466100EA2233 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "App/GoogleService-Info.plist"; sourceTree = ""; }; - AFD563141EB29B8C00EA2233 /* Messaging_Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Messaging_Example.entitlements; sourceTree = ""; }; - AFD563161EBBEF7B00EA2233 /* Data+MessagingExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+MessagingExtensions.swift"; sourceTree = ""; }; - D018534A1EDACED4003A645C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - D018534C1EDACED4003A645C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; D01853791EDAD084003A645C /* Auth_Example_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Auth_Example_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; D018537C1EDAD0E6003A645C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; D018537D1EDAD0E6003A645C /* FIRAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FIRAppDelegate.h; sourceTree = ""; }; @@ -1039,6 +1037,24 @@ DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_EarlGreyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DE26D27D1F705EC7004AE1D3 /* SwiftSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; DE45C6641E7DA8CB009E6ACD /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + DE47C0ED207AC87D00B1AEDF /* Messaging_Sample_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Messaging_Sample_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + DE47C107207AC94A00B1AEDF /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + DE47C109207AC94A00B1AEDF /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; + DE47C10A207AC94A00B1AEDF /* MessagingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagingViewController.swift; sourceTree = ""; }; + DE47C10B207AC94A00B1AEDF /* Messaging_Example.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Messaging_Example.entitlements; sourceTree = ""; }; + DE47C10D207AC94A00B1AEDF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + DE47C10F207AC94A00B1AEDF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + DE47C110207AC94A00B1AEDF /* Messaging-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Messaging-Info.plist"; sourceTree = ""; }; + DE47C111207AC94A00B1AEDF /* Data+MessagingExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+MessagingExtensions.swift"; sourceTree = ""; }; + DE47C112207AC94A00B1AEDF /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + DE47C113207AC94A00B1AEDF /* NotificationsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = ""; }; + DE47C134207ACAA900B1AEDF /* FIRAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRAppDelegate.h; sourceTree = ""; }; + DE47C135207ACAA900B1AEDF /* FIRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRViewController.h; sourceTree = ""; }; + DE47C137207ACAA900B1AEDF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + DE47C139207ACAA900B1AEDF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + DE47C13B207ACAA900B1AEDF /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + DE47C13C207ACAA900B1AEDF /* FIRAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAppDelegate.m; sourceTree = ""; }; + DE47C13D207ACAA900B1AEDF /* FIRViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRViewController.m; sourceTree = ""; }; DE53893E1FBB62E100199FC2 /* Auth_Tests_tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_Tests_tvOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DE53894C1FBB635400199FC2 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; DE53894D1FBB635400199FC2 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -1378,6 +1394,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DE47C0E4207AC87D00B1AEDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DE53893B1FBB62E100199FC2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1611,6 +1634,7 @@ DE53893E1FBB62E100199FC2 /* Auth_Tests_tvOS.xctest */, DE1FAE901FBCF5E100897AAA /* Auth_Example_tvOS.app */, DEDFEFEC1FD1B8C100F7D466 /* Analytics_Tests_iOS.xctest */, + DE47C0ED207AC87D00B1AEDF /* Messaging_Sample_iOS.app */, ); name = Products; sourceTree = ""; @@ -1650,15 +1674,6 @@ name = Shared; sourceTree = ""; }; - AFD562F71EB13CC700EA2233 /* App */ = { - isa = PBXGroup; - children = ( - AFD563131EB1466100EA2233 /* GoogleService-Info.plist */, - D01853481EDACE1A003A645C /* iOS */, - ); - name = App; - sourceTree = ""; - }; D01853461EDACC10003A645C /* iOS */ = { isa = PBXGroup; children = ( @@ -1688,23 +1703,6 @@ path = macOS; sourceTree = ""; }; - D01853481EDACE1A003A645C /* iOS */ = { - isa = PBXGroup; - children = ( - AFD563001EB13DF200EA2233 /* Messaging-Info.plist */, - AFD563141EB29B8C00EA2233 /* Messaging_Example.entitlements */, - AFD562FF1EB13DF200EA2233 /* AppDelegate.swift */, - AFD563161EBBEF7B00EA2233 /* Data+MessagingExtensions.swift */, - AFC8BA9E1EBD51A700B8EEAE /* Environment.swift */, - AFD563011EB13DF200EA2233 /* MessagingViewController.swift */, - AFC8BA9C1EBD230E00B8EEAE /* NotificationsController.swift */, - D01853491EDACED4003A645C /* LaunchScreen.storyboard */, - D018534B1EDACED4003A645C /* Main.storyboard */, - ); - name = iOS; - path = App/iOS; - sourceTree = ""; - }; D0D857F61ED9ADA8002342D2 /* iOS */ = { isa = PBXGroup; children = ( @@ -1891,6 +1889,53 @@ path = SwiftSample; sourceTree = ""; }; + DE47C106207AC94A00B1AEDF /* Sample */ = { + isa = PBXGroup; + children = ( + DE47C107207AC94A00B1AEDF /* GoogleService-Info.plist */, + DE47C108207AC94A00B1AEDF /* iOS */, + ); + path = Sample; + sourceTree = ""; + }; + DE47C108207AC94A00B1AEDF /* iOS */ = { + isa = PBXGroup; + children = ( + DE47C109207AC94A00B1AEDF /* Environment.swift */, + DE47C10A207AC94A00B1AEDF /* MessagingViewController.swift */, + DE47C10B207AC94A00B1AEDF /* Messaging_Example.entitlements */, + DE47C10C207AC94A00B1AEDF /* LaunchScreen.storyboard */, + DE47C10E207AC94A00B1AEDF /* Main.storyboard */, + DE47C110207AC94A00B1AEDF /* Messaging-Info.plist */, + DE47C111207AC94A00B1AEDF /* Data+MessagingExtensions.swift */, + DE47C112207AC94A00B1AEDF /* AppDelegate.swift */, + DE47C113207AC94A00B1AEDF /* NotificationsController.swift */, + ); + path = iOS; + sourceTree = ""; + }; + DE47C131207ACAA900B1AEDF /* App */ = { + isa = PBXGroup; + children = ( + DE47C133207ACAA900B1AEDF /* iOS */, + ); + path = App; + sourceTree = ""; + }; + DE47C133207ACAA900B1AEDF /* iOS */ = { + isa = PBXGroup; + children = ( + DE47C134207ACAA900B1AEDF /* FIRAppDelegate.h */, + DE47C135207ACAA900B1AEDF /* FIRViewController.h */, + DE47C136207ACAA900B1AEDF /* LaunchScreen.storyboard */, + DE47C138207ACAA900B1AEDF /* Main.storyboard */, + DE47C13B207ACAA900B1AEDF /* main.m */, + DE47C13C207ACAA900B1AEDF /* FIRAppDelegate.m */, + DE47C13D207ACAA900B1AEDF /* FIRViewController.m */, + ); + path = iOS; + sourceTree = ""; + }; DE53894B1FBB635400199FC2 /* tvOS */ = { isa = PBXGroup; children = ( @@ -2097,8 +2142,9 @@ DE9315B41E8738B70083EDBF /* Messaging */ = { isa = PBXGroup; children = ( + DE47C131207ACAA900B1AEDF /* App */, + DE47C106207AC94A00B1AEDF /* Sample */, AFC8BAA11EC257D700B8EEAE /* Messaging_Example-Bridging-Header.h */, - AFD562F71EB13CC700EA2233 /* App */, DE9315C21E8738B70083EDBF /* Tests */, ); path = Messaging; @@ -2596,6 +2642,23 @@ productReference = DE26D27D1F705EC7004AE1D3 /* SwiftSample.app */; productType = "com.apple.product-type.application"; }; + DE47C0DC207AC87D00B1AEDF /* Messaging_Sample_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DE47C0EA207AC87D00B1AEDF /* Build configuration list for PBXNativeTarget "Messaging_Sample_iOS" */; + buildPhases = ( + DE47C0DD207AC87D00B1AEDF /* Sources */, + DE47C0E4207AC87D00B1AEDF /* Frameworks */, + DE47C0E5207AC87D00B1AEDF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Messaging_Sample_iOS; + productName = Messaging_Example_iOS; + productReference = DE47C0ED207AC87D00B1AEDF /* Messaging_Sample_iOS.app */; + productType = "com.apple.product-type.application"; + }; DE53893D1FBB62E100199FC2 /* Auth_Tests_tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = DE5389491FBB62E100199FC2 /* Build configuration list for PBXNativeTarget "Auth_Tests_tvOS" */; @@ -2987,6 +3050,9 @@ DevelopmentTeam = EQHXZ8M8AV; ProvisioningStyle = Automatic; }; + DE47C0DC207AC87D00B1AEDF = { + DevelopmentTeam = EQHXZ8M8AV; + }; DE53893D1FBB62E100199FC2 = { CreatedOnToolsVersion = 9.1; DevelopmentTeam = EQHXZ8M8AV; @@ -3106,6 +3172,7 @@ DE1EC27E1FBA5E63007D18D8 /* Database_Tests_tvOS */, AFD562E41EB13C6D00EA2233 /* Messaging_Example_iOS */, DE9315A61E8738460083EDBF /* Messaging_Tests_iOS */, + DE47C0DC207AC87D00B1AEDF /* Messaging_Sample_iOS */, DEB139E01E73506A00AC236D /* Storage_Example_iOS */, DEB13A0A1E73507E00AC236D /* Storage_Tests_iOS */, 06121EBB1EC399C50008D70E /* Storage_IntegrationTests_iOS */, @@ -3141,10 +3208,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D018534D1EDACED4003A645C /* LaunchScreen.storyboard in Resources */, + DE47C13F207ACAA900B1AEDF /* LaunchScreen.storyboard in Resources */, + DEA7795D207ACC8000245121 /* GoogleService-Info.plist in Resources */, AFAF36F81EC28C25004BDEE5 /* Shared.xcassets in Resources */, - AFD563151EB29EDE00EA2233 /* GoogleService-Info.plist in Resources */, - D018534E1EDACED4003A645C /* Main.storyboard in Resources */, + DE47C140207ACAA900B1AEDF /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3303,6 +3370,18 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DE47C0E5207AC87D00B1AEDF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DE47C118207AC94A00B1AEDF /* Main.storyboard in Resources */, + DE47C0E7207AC87D00B1AEDF /* Shared.xcassets in Resources */, + DE47C114207AC94A00B1AEDF /* GoogleService-Info.plist in Resources */, + DE47C117207AC94A00B1AEDF /* LaunchScreen.storyboard in Resources */, + DE47C119207AC94A00B1AEDF /* Messaging-Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DE53893C1FBB62E100199FC2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -3485,12 +3564,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - AFD563171EBBEF7B00EA2233 /* Data+MessagingExtensions.swift in Sources */, - AFD5630E1EB1402300EA2233 /* AppDelegate.swift in Sources */, - AFC8BA9D1EBD230E00B8EEAE /* NotificationsController.swift in Sources */, - AFD5630F1EB1402300EA2233 /* MessagingViewController.swift in Sources */, - AFC8BAA71EC257D800B8EEAE /* FIRSampleAppUtilities.m in Sources */, - AFC8BA9F1EBD51A700B8EEAE /* Environment.swift in Sources */, + DE47C142207ACAA900B1AEDF /* main.m in Sources */, + DE47C143207ACAA900B1AEDF /* FIRAppDelegate.m in Sources */, + DE47C144207ACAA900B1AEDF /* FIRViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3796,6 +3872,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DE47C0DD207AC87D00B1AEDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DE47C11A207AC94A00B1AEDF /* Data+MessagingExtensions.swift in Sources */, + DE47C115207AC94A00B1AEDF /* Environment.swift in Sources */, + DE47C116207AC94A00B1AEDF /* MessagingViewController.swift in Sources */, + DE47C0E2207AC87D00B1AEDF /* FIRSampleAppUtilities.m in Sources */, + DE47C11C207AC94A00B1AEDF /* NotificationsController.swift in Sources */, + DE47C11B207AC94A00B1AEDF /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DE53893A1FBB62E100199FC2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -4282,22 +4371,6 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ - D01853491EDACED4003A645C /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - D018534A1EDACED4003A645C /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; - D018534B1EDACED4003A645C /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - D018534C1EDACED4003A645C /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; D018537B1EDAD0E6003A645C /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -4342,6 +4415,38 @@ name = Localizable.strings; sourceTree = ""; }; + DE47C10C207AC94A00B1AEDF /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + DE47C10D207AC94A00B1AEDF /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + DE47C10E207AC94A00B1AEDF /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + DE47C10F207AC94A00B1AEDF /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + DE47C136207ACAA900B1AEDF /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + DE47C137207ACAA900B1AEDF /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + DE47C138207ACAA900B1AEDF /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + DE47C139207ACAA900B1AEDF /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; DE7B8D2C1E8EF202009EB6DF /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -4623,11 +4728,11 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = Messaging/App/iOS/Messaging_Example.entitlements; + CODE_SIGN_ENTITLEMENTS = Messaging/Sample/iOS/Messaging_Example.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = EQHXZ8M8AV; - INFOPLIST_FILE = "Messaging/App/iOS/Messaging-Info.plist"; + INFOPLIST_FILE = "Messaging/Sample/iOS/Messaging-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = com.google.FirebaseMessagingSample.dev; @@ -4647,12 +4752,12 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = Messaging/App/iOS/Messaging_Example.entitlements; + CODE_SIGN_ENTITLEMENTS = Messaging/Sample/iOS/Messaging_Example.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = EQHXZ8M8AV; - INFOPLIST_FILE = "Messaging/App/iOS/Messaging-Info.plist"; + INFOPLIST_FILE = "Messaging/Sample/iOS/Messaging-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.google.FirebaseMessagingSample.dev; @@ -5702,6 +5807,54 @@ }; name = Release; }; + DE47C0EB207AC87D00B1AEDF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_ENTITLEMENTS = Messaging/Sample/iOS/Messaging_Example.entitlements; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = EQHXZ8M8AV; + INFOPLIST_FILE = "$(SRCROOT)/Messaging/Sample/iOS/Messaging-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.FirebaseMessagingSample.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OBJC_BRIDGING_HEADER = "Messaging/Messaging_Example-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + DE47C0EC207AC87D00B1AEDF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_ENTITLEMENTS = Messaging/Sample/iOS/Messaging_Example.entitlements; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = EQHXZ8M8AV; + INFOPLIST_FILE = "$(SRCROOT)/Messaging/Sample/iOS/Messaging-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.google.FirebaseMessagingSample.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Messaging/Messaging_Example-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; DE5389451FBB62E100199FC2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -6005,7 +6158,6 @@ DE9315B01E8738460083EDBF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -6021,6 +6173,7 @@ "\"${PODS_ROOT}/Headers/Public\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAnalytics\"", "\"${PODS_ROOT}/../../Firebase/Messaging\"", + "\"${PODS_ROOT}/Headers/Private\"", ); INFOPLIST_FILE = Messaging/Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -6034,7 +6187,6 @@ DE9315B11E8738460083EDBF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -6051,6 +6203,7 @@ "\"${PODS_ROOT}/Headers/Public\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAnalytics\"", "\"${PODS_ROOT}/../../Firebase/Messaging\"", + "\"${PODS_ROOT}/Headers/Private\"", ); INFOPLIST_FILE = Messaging/Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -6777,6 +6930,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DE47C0EA207AC87D00B1AEDF /* Build configuration list for PBXNativeTarget "Messaging_Sample_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DE47C0EB207AC87D00B1AEDF /* Debug */, + DE47C0EC207AC87D00B1AEDF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DE5389491FBB62E100199FC2 /* Build configuration list for PBXNativeTarget "Auth_Tests_tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Messaging_Sample_iOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Messaging_Sample_iOS.xcscheme new file mode 100644 index 0000000..57e31f3 --- /dev/null +++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Messaging_Sample_iOS.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/Messaging/App/GoogleService-Info.plist b/Example/Messaging/App/GoogleService-Info.plist deleted file mode 100644 index 3f7547f..0000000 --- a/Example/Messaging/App/GoogleService-Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - API_KEY - correct_api_key - TRACKING_ID - correct_tracking_id - CLIENT_ID - correct_client_id - REVERSED_CLIENT_ID - correct_reversed_client_id - GOOGLE_APP_ID - 1:123:ios:123abc - GCM_SENDER_ID - correct_gcm_sender_id - PLIST_VERSION - 1 - BUNDLE_ID - com.google.FirebaseSDKTests - PROJECT_ID - abc-xyz-123 - DATABASE_URL - https://abc-xyz-123.firebaseio.com - STORAGE_BUCKET - project-id-123.storage.firebase.com - - diff --git a/Example/Messaging/App/iOS/AppDelegate.swift b/Example/Messaging/App/iOS/AppDelegate.swift deleted file mode 100644 index 89a5120..0000000 --- a/Example/Messaging/App/iOS/AppDelegate.swift +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import UIKit -import FirebaseCore -import FirebaseMessaging -import UserNotifications - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - static let isWithinUnitTest: Bool = { - if let testClass = NSClassFromString("XCTestCase") { - return true - } else { - return false - } - }() - - static var hasPresentedInvalidServiceInfoPlistAlert = false - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - guard !AppDelegate.isWithinUnitTest else { - // During unit tests, we don't want to initialize Firebase, since by default we want to able - // to run unit tests without requiring a non-dummy GoogleService-Info.plist file - return true - } - - guard SampleAppUtilities.appContainsRealServiceInfoPlist() else { - // We can't run because the GoogleService-Info.plist file is likely the dummy file which needs - // to be replaced with a real one, or somehow the file has been removed from the app bundle. - // See: https://github.com/firebase/firebase-ios-sdk/ - // We'll present a friendly alert when the app becomes active. - return true - } - - FirebaseApp.configure() - Messaging.messaging().delegate = self - Messaging.messaging().shouldEstablishDirectChannel = true - // Just for logging to the console when we establish/tear down our socket connection. - listenForDirectChannelStateChanges(); - - NotificationsController.configure() - - if #available(iOS 8.0, *) { - // Always register for remote notifications. This will not show a prompt to the user, as by - // default it will provision silent notifications. We can use UNUserNotificationCenter to - // request authorization for user-facing notifications. - application.registerForRemoteNotifications() - } else { - // iOS 7 didn't differentiate between user-facing and other notifications, so we should just - // register for remote notifications - NotificationsController.shared.registerForUserFacingNotificationsFor(application) - } - return true - } - - func application(_ application: UIApplication, - didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { - print("APNS Token: \(deviceToken.hexByteString)") - NotificationCenter.default.post(name: APNSTokenReceivedNotification, object: nil) - if #available(iOS 8.0, *) { - } else { - // On iOS 7, receiving a device token also means our user notifications were granted, so fire - // the notification to update our user notifications UI - NotificationCenter.default.post(name: UserNotificationsChangedNotification, object: nil) - } - } - - func application(_ application: UIApplication, - didRegister notificationSettings: UIUserNotificationSettings) { - NotificationCenter.default.post(name: UserNotificationsChangedNotification, object: nil) - } - - func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - print("application:didReceiveRemoteNotification:fetchCompletionHandler: called, with notification:") - print("\(userInfo.jsonString ?? "{}")") - completionHandler(.newData) - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // If the app didn't start property due to an invalid GoogleService-Info.plist file, show an - // alert to the developer. - if !SampleAppUtilities.appContainsRealServiceInfoPlist() && - !AppDelegate.hasPresentedInvalidServiceInfoPlistAlert { - if let vc = window?.rootViewController { - SampleAppUtilities.presentAlertForInvalidServiceInfoPlistFrom(vc) - AppDelegate.hasPresentedInvalidServiceInfoPlistAlert = true - } - } - } -} - -extension AppDelegate: MessagingDelegate { - // FCM tokens are always provided here. It is called generally during app start, but may be called - // more than once, if the token is invalidated or updated. This is the right spot to upload this - // token to your application server, or to subscribe to any topics. - func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { - if let token = Messaging.messaging().fcmToken { - print("FCM Token: \(token)") - } else { - print("FCM Token: nil") - } - } - - // Direct channel data messages are delivered here, on iOS 10.0+. - // The `shouldEstablishDirectChannel` property should be be set to |true| before data messages can - // arrive. - func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) { - // Convert to pretty-print JSON - guard let prettyPrinted = remoteMessage.appData.jsonString else { - print("Received direct channel message, but could not parse as JSON: \(remoteMessage.appData)") - return - } - print("Received direct channel message:\n\(prettyPrinted)") - } -} - -extension AppDelegate { - func listenForDirectChannelStateChanges() { - NotificationCenter.default.addObserver(self, selector: #selector(onMessagingDirectChannelStateChanged(_:)), name: .MessagingConnectionStateChanged, object: nil) - } - - func onMessagingDirectChannelStateChanged(_ notification: Notification) { - print("FCM Direct Channel Established: \(Messaging.messaging().isDirectChannelEstablished)") - } -} - -extension Dictionary { - /// Utility method for printing Dictionaries as pretty-printed JSON. - var jsonString: String? { - if let jsonData = try? JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted]), - let jsonString = String(data: jsonData, encoding: .utf8) { - return jsonString - } - return nil - } -} diff --git a/Example/Messaging/App/iOS/Base.lproj/LaunchScreen.storyboard b/Example/Messaging/App/iOS/Base.lproj/LaunchScreen.storyboard index fdf3f97..66a7681 100644 --- a/Example/Messaging/App/iOS/Base.lproj/LaunchScreen.storyboard +++ b/Example/Messaging/App/iOS/Base.lproj/LaunchScreen.storyboard @@ -1,8 +1,8 @@ - - + + - - + + @@ -14,9 +14,9 @@ - + - + diff --git a/Example/Messaging/App/iOS/Base.lproj/Main.storyboard b/Example/Messaging/App/iOS/Base.lproj/Main.storyboard index 6df1a82..d164a23 100644 --- a/Example/Messaging/App/iOS/Base.lproj/Main.storyboard +++ b/Example/Messaging/App/iOS/Base.lproj/Main.storyboard @@ -1,48 +1,27 @@ - - - - - + + - - + - - + + - + - - + + - - + + - + - - + - - - - - - - - - - - - - - - - - + diff --git a/Example/Messaging/App/iOS/Data+MessagingExtensions.swift b/Example/Messaging/App/iOS/Data+MessagingExtensions.swift deleted file mode 100644 index 99ded25..0000000 --- a/Example/Messaging/App/iOS/Data+MessagingExtensions.swift +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Foundation - -extension Data { - // Print Data as a string of bytes in hex, such as the common representation of APNs device tokens - // See: http://stackoverflow.com/a/40031342/9849 - var hexByteString: String { - return self.map { String(format: "%02.2hhx", $0) }.joined() - } -} diff --git a/Example/Messaging/App/iOS/Environment.swift b/Example/Messaging/App/iOS/Environment.swift deleted file mode 100644 index 5219c64..0000000 --- a/Example/Messaging/App/iOS/Environment.swift +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Foundation - -struct Environment { - static let isSimulator: Bool = { - var isSim = false - #if arch(i386) || arch(x86_64) - isSim = true - #endif - - return isSim - }() -} diff --git a/Example/Messaging/App/iOS/FIRAppDelegate.h b/Example/Messaging/App/iOS/FIRAppDelegate.h new file mode 100644 index 0000000..1eb5040 --- /dev/null +++ b/Example/Messaging/App/iOS/FIRAppDelegate.h @@ -0,0 +1,23 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import UIKit; + +@interface FIRAppDelegate : UIResponder + +@property(strong, nonatomic) UIWindow *window; + +@end diff --git a/Example/Messaging/App/iOS/FIRAppDelegate.m b/Example/Messaging/App/iOS/FIRAppDelegate.m new file mode 100644 index 0000000..535e529 --- /dev/null +++ b/Example/Messaging/App/iOS/FIRAppDelegate.m @@ -0,0 +1,58 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FIRAppDelegate.h" + +#import + +@implementation FIRAppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [FIRApp configure]; + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for + // certain types of temporary interruptions (such as an incoming phone call or SMS message) or + // when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame + // rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store + // enough application state information to restore your application to its current state in case + // it is terminated later. + // If your application supports background execution, this method is called instead of + // applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo + // many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If + // the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also + // applicationDidEnterBackground:. +} + +@end diff --git a/Example/Messaging/App/iOS/FIRViewController.h b/Example/Messaging/App/iOS/FIRViewController.h new file mode 100644 index 0000000..64b4b74 --- /dev/null +++ b/Example/Messaging/App/iOS/FIRViewController.h @@ -0,0 +1,21 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import UIKit; + +@interface FIRViewController : UIViewController + +@end diff --git a/Example/Messaging/App/iOS/FIRViewController.m b/Example/Messaging/App/iOS/FIRViewController.m new file mode 100644 index 0000000..027aabf --- /dev/null +++ b/Example/Messaging/App/iOS/FIRViewController.m @@ -0,0 +1,33 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FIRViewController.h" + +@interface FIRViewController () + +@end + +@implementation FIRViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/Example/Messaging/App/iOS/Messaging-Info.plist b/Example/Messaging/App/iOS/Messaging-Info.plist deleted file mode 100644 index b43105e..0000000 --- a/Example/Messaging/App/iOS/Messaging-Info.plist +++ /dev/null @@ -1,55 +0,0 @@ - - - - - FirebaseMessagingAutoInitEnabled - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - UIBackgroundModes - - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Example/Messaging/App/iOS/MessagingViewController.swift b/Example/Messaging/App/iOS/MessagingViewController.swift deleted file mode 100644 index 9bd07c1..0000000 --- a/Example/Messaging/App/iOS/MessagingViewController.swift +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import UIKit - -import FirebaseMessaging - -enum Row: String { - case apnsToken = "apnsToken" - case apnsStatus = "apnsStatus" - case requestAPNSPermissions = "requestAPNSPermissions" - case fcmToken = "fcmToken" -} - -enum PermissionsButtonTitle: String { - case requestPermissions = "Request User Notifications" - case noAPNS = "Cannot Request Permissions (No APNs)" - case alreadyRequested = "Already Requested Permissions" - case simulator = "Cannot Request Permissions (Simulator)" -} - -class MessagingViewController: UIViewController { - - let tableView: UITableView - - var sections = [[Row]]() - var sectionHeaderTitles = [String?]() - - var allowedNotificationTypes: [NotificationsControllerAllowedNotificationType]? - - // Cached rows by Row type. Since this is largely a fixed table view, we'll - // keep track of our created cells and UI, rather than have all the logic - - required init?(coder aDecoder: NSCoder) { - tableView = UITableView(frame: CGRect.zero, style: .grouped) - tableView.rowHeight = UITableViewAutomaticDimension - tableView.estimatedRowHeight = 44 - // Allow UI Controls within the table to be immediately responsive - tableView.delaysContentTouches = false - super.init(coder: aDecoder) - tableView.dataSource = self - tableView.delegate = self - } - - override func loadView() { - super.loadView() - view = UIView(frame: CGRect.zero) - view.addSubview(self.tableView) - // Ensure that the tableView always is the size of the view - tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - } - - override func viewDidLoad() { - super.viewDidLoad() - let center = NotificationCenter.default - center.addObserver(self, - selector: #selector(onAPNSTokenReceived) , - name: APNSTokenReceivedNotification, - object: nil) - center.addObserver(self, - selector: #selector(onUserNotificationSettingsChanged), - name: UserNotificationsChangedNotification, - object: nil) - center.addObserver(self, - selector: #selector(onFCMTokenRefreshed), - name: Notification.Name.MessagingRegistrationTokenRefreshed, - object: nil) - updateAllowedNotificationTypes { - self.resetTableContents() - self.tableView.reloadData() - } - } - - func onAPNSTokenReceived() { - // Reload the appropriate cells - updateAllowedNotificationTypes { - if let tokenPath = self.indexPathFor(.apnsToken), - let statusPath = self.indexPathFor(.apnsStatus), - let requestPath = self.indexPathFor(.requestAPNSPermissions) { - self.updateIndexPaths(indexPaths: [tokenPath, statusPath, requestPath]) - } - } - } - - func onFCMTokenRefreshed() { - if let indexPath = indexPathFor(.fcmToken) { - updateIndexPaths(indexPaths: [indexPath]) - } - } - - func onUserNotificationSettingsChanged() { - updateAllowedNotificationTypes { - if let statusPath = self.indexPathFor(.apnsStatus), - let requestPath = self.indexPathFor(.requestAPNSPermissions) { - self.updateIndexPaths(indexPaths: [statusPath, requestPath]) - } - } - } - - private func updateIndexPaths(indexPaths: [IndexPath]) { - tableView.beginUpdates() - tableView.reloadRows(at: indexPaths, with: .none) - tableView.endUpdates() - } - - fileprivate func updateAllowedNotificationTypes(_ completion: (() -> Void)?) { - NotificationsController.shared.getAllowedNotificationTypes { (types) in - self.allowedNotificationTypes = types - self.updateRequestAPNSButton() - completion?() - } - } - - fileprivate func updateRequestAPNSButton() { - guard !Environment.isSimulator else { - requestPermissionsButton.isEnabled = false - requestPermissionsButton.setTitle(PermissionsButtonTitle.simulator.rawValue, for: .normal) - return - } - guard let allowedTypes = allowedNotificationTypes else { - requestPermissionsButton.isEnabled = false - requestPermissionsButton.setTitle(PermissionsButtonTitle.noAPNS.rawValue, for: .normal) - return - } - - requestPermissionsButton.isEnabled = - (allowedTypes.count == 1 && allowedTypes.first! == .silent) - - let title: PermissionsButtonTitle = - (requestPermissionsButton.isEnabled ? .requestPermissions : .alreadyRequested) - requestPermissionsButton.setTitle(title.rawValue, for: .normal) - } - - // MARK: UI (Cells and Buttons) Defined as lazy properties - lazy var apnsTableCell: UITableViewCell = { - let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.apnsToken.rawValue) - cell.textLabel?.numberOfLines = 0 - cell.textLabel?.lineBreakMode = .byWordWrapping - return cell - }() - - lazy var apnsStatusTableCell: UITableViewCell = { - let cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: Row.apnsStatus.rawValue) - cell.textLabel?.text = "Allowed:" - cell.detailTextLabel?.numberOfLines = 0 - cell.detailTextLabel?.lineBreakMode = .byWordWrapping - return cell - }() - - lazy var requestPermissionsButton: UIButton = { - let button = UIButton(type: .system) - button.setTitle(PermissionsButtonTitle.requestPermissions.rawValue, for: .normal) - button.setTitleColor(UIColor.gray, for: .highlighted) - button.setTitleColor(UIColor.gray, for: .disabled) - button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) - button.addTarget(self, - action: #selector(onRequestUserNotificationsButtonTapped), - for: .touchUpInside) - return button - }() - - lazy var apnsRequestPermissionsTableCell: UITableViewCell = { - let cell = UITableViewCell(style: .default, - reuseIdentifier: Row.requestAPNSPermissions.rawValue) - cell.selectionStyle = .none - cell.contentView.addSubview(self.requestPermissionsButton) - self.requestPermissionsButton.frame = cell.contentView.bounds - self.requestPermissionsButton.autoresizingMask = [.flexibleWidth, .flexibleHeight] - return cell - }() - - lazy var fcmTokenTableCell: UITableViewCell = { - let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.fcmToken.rawValue) - cell.textLabel?.numberOfLines = 0 - cell.textLabel?.lineBreakMode = .byCharWrapping - return cell - }() -} - -// MARK: - Configuring the table view and cells with information -extension MessagingViewController { - func resetTableContents() { - sections.removeAll() - sectionHeaderTitles.removeAll() - - // APNS - let apnsSection: [Row] = [.apnsToken, .apnsStatus, .requestAPNSPermissions] - sections.append(apnsSection) - sectionHeaderTitles.append("APNs") - - // FCM - let fcmSection: [Row] = [.fcmToken] - sections.append(fcmSection) - sectionHeaderTitles.append("FCM Token") - - } - - func indexPathFor(_ rowId: Row) -> IndexPath? { - var sectionIndex = 0 - for section in sections { - var rowIndex = 0 - for row in section { - if row == rowId { - return IndexPath(row: rowIndex, section: sectionIndex) - } - rowIndex += 1 - } - sectionIndex += 1 - } - return nil - } - - func configureCell(_ cell: UITableViewCell, withAPNSToken apnsToken: Data?) { - guard !Environment.isSimulator else { - cell.textLabel?.text = "APNs notifications are not supported in the simulator." - cell.detailTextLabel?.text = nil - return - } - if let apnsToken = apnsToken { - cell.textLabel?.text = apnsToken.hexByteString - cell.detailTextLabel?.text = "Tap to Share" - } else { - cell.textLabel?.text = "None" - cell.detailTextLabel?.text = nil - } - } - - func configureCellWithAPNSStatus(_ cell: UITableViewCell) { - if let allowedNotificationTypes = allowedNotificationTypes { - let displayableTypes: [String] = allowedNotificationTypes.map { return $0.rawValue } - cell.detailTextLabel?.text = displayableTypes.joined(separator: ", ") - } else { - cell.detailTextLabel?.text = "Retrieving..." - } - } - - func configureCell(_ cell: UITableViewCell, withFCMToken fcmToken: String?) { - if let fcmToken = fcmToken { - cell.textLabel?.text = fcmToken - cell.detailTextLabel?.text = "Tap to Share" - } else { - cell.textLabel?.text = "None" - cell.detailTextLabel?.text = nil - } - } -} - -// MARK: - UITableViewDataSource -extension MessagingViewController: UITableViewDataSource { - func numberOfSections(in tableView: UITableView) -> Int { - return sections.count - } - - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return sections[section].count - } - - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let row = sections[indexPath.section][indexPath.row] - - let cell: UITableViewCell - switch row { - case .apnsToken: - cell = apnsTableCell - configureCell(cell, withAPNSToken: Messaging.messaging().apnsToken) - case .apnsStatus: - cell = apnsStatusTableCell - configureCellWithAPNSStatus(cell) - case .requestAPNSPermissions: - cell = apnsRequestPermissionsTableCell - case .fcmToken: - cell = fcmTokenTableCell - configureCell(cell, withFCMToken: Messaging.messaging().fcmToken) - } - return cell - } - - func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return sectionHeaderTitles[section] - } -} - -// MARK: - UITableViewDelegate -extension MessagingViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: true) - - let row = sections[indexPath.section][indexPath.row] - switch row { - case .apnsToken: - if let apnsToken = Messaging.messaging().apnsToken { - showActivityViewControllerFor(sharedItem: apnsToken.hexByteString) - } - case .fcmToken: - if let fcmToken = Messaging.messaging().fcmToken { - showActivityViewControllerFor(sharedItem: fcmToken) - } - default: break - } - } -} - -// MARK: - UI Controls -extension MessagingViewController { - func onRequestUserNotificationsButtonTapped(sender: UIButton) { - NotificationsController.shared.registerForUserFacingNotificationsFor(UIApplication.shared) - } -} - -// MARK: - Activity View Controller -extension MessagingViewController { - func showActivityViewControllerFor(sharedItem: Any) { - let activityViewController = UIActivityViewController(activityItems: [sharedItem], - applicationActivities: nil) - present(activityViewController, animated: true, completion: nil) - } -} - diff --git a/Example/Messaging/App/iOS/Messaging_Example.entitlements b/Example/Messaging/App/iOS/Messaging_Example.entitlements deleted file mode 100644 index 903def2..0000000 --- a/Example/Messaging/App/iOS/Messaging_Example.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - aps-environment - development - - diff --git a/Example/Messaging/App/iOS/NotificationsController.swift b/Example/Messaging/App/iOS/NotificationsController.swift deleted file mode 100644 index 7545b44..0000000 --- a/Example/Messaging/App/iOS/NotificationsController.swift +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import UIKit -import UserNotifications - -import FirebaseMessaging - -enum NotificationsControllerAllowedNotificationType: String { - case none = "None" - case silent = "Silent Updates" - case alert = "Alerts" - case badge = "Badges" - case sound = "Sounds" -} - -let APNSTokenReceivedNotification: Notification.Name - = Notification.Name(rawValue: "APNSTokenReceivedNotification") -let UserNotificationsChangedNotification: Notification.Name - = Notification.Name(rawValue: "UserNotificationsChangedNotification") - -class NotificationsController: NSObject { - - static let shared: NotificationsController = { - let instance = NotificationsController() - return instance - }() - - class func configure() { - let sharedController = NotificationsController.shared - // Always become the delegate of UNUserNotificationCenter, even before we've requested user - // permissions - if #available(iOS 10.0, *) { - UNUserNotificationCenter.current().delegate = sharedController - } - } - - func registerForUserFacingNotificationsFor(_ application: UIApplication) { - if #available(iOS 10.0, *) { - UNUserNotificationCenter.current() - .requestAuthorization(options: [.alert, .badge, .sound], - completionHandler: { (granted, error) in - NotificationCenter.default.post(name: UserNotificationsChangedNotification, object: nil) - }) - } else if #available(iOS 8.0, *) { - let userNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], - categories: []) - application.registerUserNotificationSettings(userNotificationSettings) - - } else { - application.registerForRemoteNotifications(matching: [.alert, .badge, .sound]) - } - } - - func getAllowedNotificationTypes(_ completion: - @escaping (_ allowedTypes: [NotificationsControllerAllowedNotificationType]) -> Void) { - - guard Messaging.messaging().apnsToken != nil else { - completion([.none]) - return - } - - var types: [NotificationsControllerAllowedNotificationType] = [.silent] - if #available(iOS 10.0, *) { - UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings) in - if settings.alertSetting == .enabled { - types.append(.alert) - } - if settings.badgeSetting == .enabled { - types.append(.badge) - } - if settings.soundSetting == .enabled { - types.append(.sound) - } - DispatchQueue.main.async { - completion(types) - } - }) - } else if #available(iOS 8.0, *) { - if let userNotificationSettings = UIApplication.shared.currentUserNotificationSettings { - if userNotificationSettings.types.contains(.alert) { - types.append(.alert) - } - if userNotificationSettings.types.contains(.badge) { - types.append(.badge) - } - if userNotificationSettings.types.contains(.sound) { - types.append(.sound) - } - } - completion(types) - } else { - let enabledTypes = UIApplication.shared.enabledRemoteNotificationTypes() - if enabledTypes.contains(.alert) { - types.append(.alert) - } - if enabledTypes.contains(.badge) { - types.append(.badge) - } - if enabledTypes.contains(.sound) { - types.append(.sound) - } - completion(types) - } - } -} - -// MARK: - UNUserNotificationCenterDelegate -@available(iOS 10.0, *) -extension NotificationsController: UNUserNotificationCenterDelegate { - func userNotificationCenter(_ center: UNUserNotificationCenter, - willPresent notification: UNNotification, - withCompletionHandler completionHandler: - @escaping (UNNotificationPresentationOptions) -> Void) { - // Always show the incoming notification, even if the app is in foreground - print("Received notification in foreground:") - let jsonString = notification.request.content.userInfo.jsonString ?? "{}" - print("\(jsonString)") - completionHandler([.alert, .badge, .sound]) - } - - func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { - print("Received notification response") - let jsonString = response.notification.request.content.userInfo.jsonString ?? "{}" - print("\(jsonString)") - completionHandler() - } -} diff --git a/Example/Messaging/App/iOS/main.m b/Example/Messaging/App/iOS/main.m new file mode 100644 index 0000000..39c05a5 --- /dev/null +++ b/Example/Messaging/App/iOS/main.m @@ -0,0 +1,22 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import UIKit; +#import "FIRAppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([FIRAppDelegate class])); + } +} diff --git a/Example/Messaging/Sample/GoogleService-Info.plist b/Example/Messaging/Sample/GoogleService-Info.plist new file mode 100644 index 0000000..3f7547f --- /dev/null +++ b/Example/Messaging/Sample/GoogleService-Info.plist @@ -0,0 +1,28 @@ + + + + + API_KEY + correct_api_key + TRACKING_ID + correct_tracking_id + CLIENT_ID + correct_client_id + REVERSED_CLIENT_ID + correct_reversed_client_id + GOOGLE_APP_ID + 1:123:ios:123abc + GCM_SENDER_ID + correct_gcm_sender_id + PLIST_VERSION + 1 + BUNDLE_ID + com.google.FirebaseSDKTests + PROJECT_ID + abc-xyz-123 + DATABASE_URL + https://abc-xyz-123.firebaseio.com + STORAGE_BUCKET + project-id-123.storage.firebase.com + + diff --git a/Example/Messaging/Sample/iOS/AppDelegate.swift b/Example/Messaging/Sample/iOS/AppDelegate.swift new file mode 100644 index 0000000..89a5120 --- /dev/null +++ b/Example/Messaging/Sample/iOS/AppDelegate.swift @@ -0,0 +1,153 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import UIKit +import FirebaseCore +import FirebaseMessaging +import UserNotifications + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + static let isWithinUnitTest: Bool = { + if let testClass = NSClassFromString("XCTestCase") { + return true + } else { + return false + } + }() + + static var hasPresentedInvalidServiceInfoPlistAlert = false + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + guard !AppDelegate.isWithinUnitTest else { + // During unit tests, we don't want to initialize Firebase, since by default we want to able + // to run unit tests without requiring a non-dummy GoogleService-Info.plist file + return true + } + + guard SampleAppUtilities.appContainsRealServiceInfoPlist() else { + // We can't run because the GoogleService-Info.plist file is likely the dummy file which needs + // to be replaced with a real one, or somehow the file has been removed from the app bundle. + // See: https://github.com/firebase/firebase-ios-sdk/ + // We'll present a friendly alert when the app becomes active. + return true + } + + FirebaseApp.configure() + Messaging.messaging().delegate = self + Messaging.messaging().shouldEstablishDirectChannel = true + // Just for logging to the console when we establish/tear down our socket connection. + listenForDirectChannelStateChanges(); + + NotificationsController.configure() + + if #available(iOS 8.0, *) { + // Always register for remote notifications. This will not show a prompt to the user, as by + // default it will provision silent notifications. We can use UNUserNotificationCenter to + // request authorization for user-facing notifications. + application.registerForRemoteNotifications() + } else { + // iOS 7 didn't differentiate between user-facing and other notifications, so we should just + // register for remote notifications + NotificationsController.shared.registerForUserFacingNotificationsFor(application) + } + return true + } + + func application(_ application: UIApplication, + didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + print("APNS Token: \(deviceToken.hexByteString)") + NotificationCenter.default.post(name: APNSTokenReceivedNotification, object: nil) + if #available(iOS 8.0, *) { + } else { + // On iOS 7, receiving a device token also means our user notifications were granted, so fire + // the notification to update our user notifications UI + NotificationCenter.default.post(name: UserNotificationsChangedNotification, object: nil) + } + } + + func application(_ application: UIApplication, + didRegister notificationSettings: UIUserNotificationSettings) { + NotificationCenter.default.post(name: UserNotificationsChangedNotification, object: nil) + } + + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + print("application:didReceiveRemoteNotification:fetchCompletionHandler: called, with notification:") + print("\(userInfo.jsonString ?? "{}")") + completionHandler(.newData) + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // If the app didn't start property due to an invalid GoogleService-Info.plist file, show an + // alert to the developer. + if !SampleAppUtilities.appContainsRealServiceInfoPlist() && + !AppDelegate.hasPresentedInvalidServiceInfoPlistAlert { + if let vc = window?.rootViewController { + SampleAppUtilities.presentAlertForInvalidServiceInfoPlistFrom(vc) + AppDelegate.hasPresentedInvalidServiceInfoPlistAlert = true + } + } + } +} + +extension AppDelegate: MessagingDelegate { + // FCM tokens are always provided here. It is called generally during app start, but may be called + // more than once, if the token is invalidated or updated. This is the right spot to upload this + // token to your application server, or to subscribe to any topics. + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { + if let token = Messaging.messaging().fcmToken { + print("FCM Token: \(token)") + } else { + print("FCM Token: nil") + } + } + + // Direct channel data messages are delivered here, on iOS 10.0+. + // The `shouldEstablishDirectChannel` property should be be set to |true| before data messages can + // arrive. + func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) { + // Convert to pretty-print JSON + guard let prettyPrinted = remoteMessage.appData.jsonString else { + print("Received direct channel message, but could not parse as JSON: \(remoteMessage.appData)") + return + } + print("Received direct channel message:\n\(prettyPrinted)") + } +} + +extension AppDelegate { + func listenForDirectChannelStateChanges() { + NotificationCenter.default.addObserver(self, selector: #selector(onMessagingDirectChannelStateChanged(_:)), name: .MessagingConnectionStateChanged, object: nil) + } + + func onMessagingDirectChannelStateChanged(_ notification: Notification) { + print("FCM Direct Channel Established: \(Messaging.messaging().isDirectChannelEstablished)") + } +} + +extension Dictionary { + /// Utility method for printing Dictionaries as pretty-printed JSON. + var jsonString: String? { + if let jsonData = try? JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted]), + let jsonString = String(data: jsonData, encoding: .utf8) { + return jsonString + } + return nil + } +} diff --git a/Example/Messaging/Sample/iOS/Base.lproj/LaunchScreen.storyboard b/Example/Messaging/Sample/iOS/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Example/Messaging/Sample/iOS/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/Messaging/Sample/iOS/Base.lproj/Main.storyboard b/Example/Messaging/Sample/iOS/Base.lproj/Main.storyboard new file mode 100644 index 0000000..6df1a82 --- /dev/null +++ b/Example/Messaging/Sample/iOS/Base.lproj/Main.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/Messaging/Sample/iOS/Data+MessagingExtensions.swift b/Example/Messaging/Sample/iOS/Data+MessagingExtensions.swift new file mode 100644 index 0000000..99ded25 --- /dev/null +++ b/Example/Messaging/Sample/iOS/Data+MessagingExtensions.swift @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation + +extension Data { + // Print Data as a string of bytes in hex, such as the common representation of APNs device tokens + // See: http://stackoverflow.com/a/40031342/9849 + var hexByteString: String { + return self.map { String(format: "%02.2hhx", $0) }.joined() + } +} diff --git a/Example/Messaging/Sample/iOS/Environment.swift b/Example/Messaging/Sample/iOS/Environment.swift new file mode 100644 index 0000000..5219c64 --- /dev/null +++ b/Example/Messaging/Sample/iOS/Environment.swift @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation + +struct Environment { + static let isSimulator: Bool = { + var isSim = false + #if arch(i386) || arch(x86_64) + isSim = true + #endif + + return isSim + }() +} diff --git a/Example/Messaging/Sample/iOS/Messaging-Info.plist b/Example/Messaging/Sample/iOS/Messaging-Info.plist new file mode 100644 index 0000000..b43105e --- /dev/null +++ b/Example/Messaging/Sample/iOS/Messaging-Info.plist @@ -0,0 +1,55 @@ + + + + + FirebaseMessagingAutoInitEnabled + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIBackgroundModes + + remote-notification + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Example/Messaging/Sample/iOS/MessagingViewController.swift b/Example/Messaging/Sample/iOS/MessagingViewController.swift new file mode 100644 index 0000000..9bd07c1 --- /dev/null +++ b/Example/Messaging/Sample/iOS/MessagingViewController.swift @@ -0,0 +1,332 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import UIKit + +import FirebaseMessaging + +enum Row: String { + case apnsToken = "apnsToken" + case apnsStatus = "apnsStatus" + case requestAPNSPermissions = "requestAPNSPermissions" + case fcmToken = "fcmToken" +} + +enum PermissionsButtonTitle: String { + case requestPermissions = "Request User Notifications" + case noAPNS = "Cannot Request Permissions (No APNs)" + case alreadyRequested = "Already Requested Permissions" + case simulator = "Cannot Request Permissions (Simulator)" +} + +class MessagingViewController: UIViewController { + + let tableView: UITableView + + var sections = [[Row]]() + var sectionHeaderTitles = [String?]() + + var allowedNotificationTypes: [NotificationsControllerAllowedNotificationType]? + + // Cached rows by Row type. Since this is largely a fixed table view, we'll + // keep track of our created cells and UI, rather than have all the logic + + required init?(coder aDecoder: NSCoder) { + tableView = UITableView(frame: CGRect.zero, style: .grouped) + tableView.rowHeight = UITableViewAutomaticDimension + tableView.estimatedRowHeight = 44 + // Allow UI Controls within the table to be immediately responsive + tableView.delaysContentTouches = false + super.init(coder: aDecoder) + tableView.dataSource = self + tableView.delegate = self + } + + override func loadView() { + super.loadView() + view = UIView(frame: CGRect.zero) + view.addSubview(self.tableView) + // Ensure that the tableView always is the size of the view + tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + } + + override func viewDidLoad() { + super.viewDidLoad() + let center = NotificationCenter.default + center.addObserver(self, + selector: #selector(onAPNSTokenReceived) , + name: APNSTokenReceivedNotification, + object: nil) + center.addObserver(self, + selector: #selector(onUserNotificationSettingsChanged), + name: UserNotificationsChangedNotification, + object: nil) + center.addObserver(self, + selector: #selector(onFCMTokenRefreshed), + name: Notification.Name.MessagingRegistrationTokenRefreshed, + object: nil) + updateAllowedNotificationTypes { + self.resetTableContents() + self.tableView.reloadData() + } + } + + func onAPNSTokenReceived() { + // Reload the appropriate cells + updateAllowedNotificationTypes { + if let tokenPath = self.indexPathFor(.apnsToken), + let statusPath = self.indexPathFor(.apnsStatus), + let requestPath = self.indexPathFor(.requestAPNSPermissions) { + self.updateIndexPaths(indexPaths: [tokenPath, statusPath, requestPath]) + } + } + } + + func onFCMTokenRefreshed() { + if let indexPath = indexPathFor(.fcmToken) { + updateIndexPaths(indexPaths: [indexPath]) + } + } + + func onUserNotificationSettingsChanged() { + updateAllowedNotificationTypes { + if let statusPath = self.indexPathFor(.apnsStatus), + let requestPath = self.indexPathFor(.requestAPNSPermissions) { + self.updateIndexPaths(indexPaths: [statusPath, requestPath]) + } + } + } + + private func updateIndexPaths(indexPaths: [IndexPath]) { + tableView.beginUpdates() + tableView.reloadRows(at: indexPaths, with: .none) + tableView.endUpdates() + } + + fileprivate func updateAllowedNotificationTypes(_ completion: (() -> Void)?) { + NotificationsController.shared.getAllowedNotificationTypes { (types) in + self.allowedNotificationTypes = types + self.updateRequestAPNSButton() + completion?() + } + } + + fileprivate func updateRequestAPNSButton() { + guard !Environment.isSimulator else { + requestPermissionsButton.isEnabled = false + requestPermissionsButton.setTitle(PermissionsButtonTitle.simulator.rawValue, for: .normal) + return + } + guard let allowedTypes = allowedNotificationTypes else { + requestPermissionsButton.isEnabled = false + requestPermissionsButton.setTitle(PermissionsButtonTitle.noAPNS.rawValue, for: .normal) + return + } + + requestPermissionsButton.isEnabled = + (allowedTypes.count == 1 && allowedTypes.first! == .silent) + + let title: PermissionsButtonTitle = + (requestPermissionsButton.isEnabled ? .requestPermissions : .alreadyRequested) + requestPermissionsButton.setTitle(title.rawValue, for: .normal) + } + + // MARK: UI (Cells and Buttons) Defined as lazy properties + lazy var apnsTableCell: UITableViewCell = { + let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.apnsToken.rawValue) + cell.textLabel?.numberOfLines = 0 + cell.textLabel?.lineBreakMode = .byWordWrapping + return cell + }() + + lazy var apnsStatusTableCell: UITableViewCell = { + let cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: Row.apnsStatus.rawValue) + cell.textLabel?.text = "Allowed:" + cell.detailTextLabel?.numberOfLines = 0 + cell.detailTextLabel?.lineBreakMode = .byWordWrapping + return cell + }() + + lazy var requestPermissionsButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle(PermissionsButtonTitle.requestPermissions.rawValue, for: .normal) + button.setTitleColor(UIColor.gray, for: .highlighted) + button.setTitleColor(UIColor.gray, for: .disabled) + button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) + button.addTarget(self, + action: #selector(onRequestUserNotificationsButtonTapped), + for: .touchUpInside) + return button + }() + + lazy var apnsRequestPermissionsTableCell: UITableViewCell = { + let cell = UITableViewCell(style: .default, + reuseIdentifier: Row.requestAPNSPermissions.rawValue) + cell.selectionStyle = .none + cell.contentView.addSubview(self.requestPermissionsButton) + self.requestPermissionsButton.frame = cell.contentView.bounds + self.requestPermissionsButton.autoresizingMask = [.flexibleWidth, .flexibleHeight] + return cell + }() + + lazy var fcmTokenTableCell: UITableViewCell = { + let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.fcmToken.rawValue) + cell.textLabel?.numberOfLines = 0 + cell.textLabel?.lineBreakMode = .byCharWrapping + return cell + }() +} + +// MARK: - Configuring the table view and cells with information +extension MessagingViewController { + func resetTableContents() { + sections.removeAll() + sectionHeaderTitles.removeAll() + + // APNS + let apnsSection: [Row] = [.apnsToken, .apnsStatus, .requestAPNSPermissions] + sections.append(apnsSection) + sectionHeaderTitles.append("APNs") + + // FCM + let fcmSection: [Row] = [.fcmToken] + sections.append(fcmSection) + sectionHeaderTitles.append("FCM Token") + + } + + func indexPathFor(_ rowId: Row) -> IndexPath? { + var sectionIndex = 0 + for section in sections { + var rowIndex = 0 + for row in section { + if row == rowId { + return IndexPath(row: rowIndex, section: sectionIndex) + } + rowIndex += 1 + } + sectionIndex += 1 + } + return nil + } + + func configureCell(_ cell: UITableViewCell, withAPNSToken apnsToken: Data?) { + guard !Environment.isSimulator else { + cell.textLabel?.text = "APNs notifications are not supported in the simulator." + cell.detailTextLabel?.text = nil + return + } + if let apnsToken = apnsToken { + cell.textLabel?.text = apnsToken.hexByteString + cell.detailTextLabel?.text = "Tap to Share" + } else { + cell.textLabel?.text = "None" + cell.detailTextLabel?.text = nil + } + } + + func configureCellWithAPNSStatus(_ cell: UITableViewCell) { + if let allowedNotificationTypes = allowedNotificationTypes { + let displayableTypes: [String] = allowedNotificationTypes.map { return $0.rawValue } + cell.detailTextLabel?.text = displayableTypes.joined(separator: ", ") + } else { + cell.detailTextLabel?.text = "Retrieving..." + } + } + + func configureCell(_ cell: UITableViewCell, withFCMToken fcmToken: String?) { + if let fcmToken = fcmToken { + cell.textLabel?.text = fcmToken + cell.detailTextLabel?.text = "Tap to Share" + } else { + cell.textLabel?.text = "None" + cell.detailTextLabel?.text = nil + } + } +} + +// MARK: - UITableViewDataSource +extension MessagingViewController: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return sections.count + } + + public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return sections[section].count + } + + public func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let row = sections[indexPath.section][indexPath.row] + + let cell: UITableViewCell + switch row { + case .apnsToken: + cell = apnsTableCell + configureCell(cell, withAPNSToken: Messaging.messaging().apnsToken) + case .apnsStatus: + cell = apnsStatusTableCell + configureCellWithAPNSStatus(cell) + case .requestAPNSPermissions: + cell = apnsRequestPermissionsTableCell + case .fcmToken: + cell = fcmTokenTableCell + configureCell(cell, withFCMToken: Messaging.messaging().fcmToken) + } + return cell + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return sectionHeaderTitles[section] + } +} + +// MARK: - UITableViewDelegate +extension MessagingViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let row = sections[indexPath.section][indexPath.row] + switch row { + case .apnsToken: + if let apnsToken = Messaging.messaging().apnsToken { + showActivityViewControllerFor(sharedItem: apnsToken.hexByteString) + } + case .fcmToken: + if let fcmToken = Messaging.messaging().fcmToken { + showActivityViewControllerFor(sharedItem: fcmToken) + } + default: break + } + } +} + +// MARK: - UI Controls +extension MessagingViewController { + func onRequestUserNotificationsButtonTapped(sender: UIButton) { + NotificationsController.shared.registerForUserFacingNotificationsFor(UIApplication.shared) + } +} + +// MARK: - Activity View Controller +extension MessagingViewController { + func showActivityViewControllerFor(sharedItem: Any) { + let activityViewController = UIActivityViewController(activityItems: [sharedItem], + applicationActivities: nil) + present(activityViewController, animated: true, completion: nil) + } +} + diff --git a/Example/Messaging/Sample/iOS/Messaging_Example.entitlements b/Example/Messaging/Sample/iOS/Messaging_Example.entitlements new file mode 100644 index 0000000..903def2 --- /dev/null +++ b/Example/Messaging/Sample/iOS/Messaging_Example.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/Example/Messaging/Sample/iOS/NotificationsController.swift b/Example/Messaging/Sample/iOS/NotificationsController.swift new file mode 100644 index 0000000..7545b44 --- /dev/null +++ b/Example/Messaging/Sample/iOS/NotificationsController.swift @@ -0,0 +1,141 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import UIKit +import UserNotifications + +import FirebaseMessaging + +enum NotificationsControllerAllowedNotificationType: String { + case none = "None" + case silent = "Silent Updates" + case alert = "Alerts" + case badge = "Badges" + case sound = "Sounds" +} + +let APNSTokenReceivedNotification: Notification.Name + = Notification.Name(rawValue: "APNSTokenReceivedNotification") +let UserNotificationsChangedNotification: Notification.Name + = Notification.Name(rawValue: "UserNotificationsChangedNotification") + +class NotificationsController: NSObject { + + static let shared: NotificationsController = { + let instance = NotificationsController() + return instance + }() + + class func configure() { + let sharedController = NotificationsController.shared + // Always become the delegate of UNUserNotificationCenter, even before we've requested user + // permissions + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = sharedController + } + } + + func registerForUserFacingNotificationsFor(_ application: UIApplication) { + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current() + .requestAuthorization(options: [.alert, .badge, .sound], + completionHandler: { (granted, error) in + NotificationCenter.default.post(name: UserNotificationsChangedNotification, object: nil) + }) + } else if #available(iOS 8.0, *) { + let userNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], + categories: []) + application.registerUserNotificationSettings(userNotificationSettings) + + } else { + application.registerForRemoteNotifications(matching: [.alert, .badge, .sound]) + } + } + + func getAllowedNotificationTypes(_ completion: + @escaping (_ allowedTypes: [NotificationsControllerAllowedNotificationType]) -> Void) { + + guard Messaging.messaging().apnsToken != nil else { + completion([.none]) + return + } + + var types: [NotificationsControllerAllowedNotificationType] = [.silent] + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings) in + if settings.alertSetting == .enabled { + types.append(.alert) + } + if settings.badgeSetting == .enabled { + types.append(.badge) + } + if settings.soundSetting == .enabled { + types.append(.sound) + } + DispatchQueue.main.async { + completion(types) + } + }) + } else if #available(iOS 8.0, *) { + if let userNotificationSettings = UIApplication.shared.currentUserNotificationSettings { + if userNotificationSettings.types.contains(.alert) { + types.append(.alert) + } + if userNotificationSettings.types.contains(.badge) { + types.append(.badge) + } + if userNotificationSettings.types.contains(.sound) { + types.append(.sound) + } + } + completion(types) + } else { + let enabledTypes = UIApplication.shared.enabledRemoteNotificationTypes() + if enabledTypes.contains(.alert) { + types.append(.alert) + } + if enabledTypes.contains(.badge) { + types.append(.badge) + } + if enabledTypes.contains(.sound) { + types.append(.sound) + } + completion(types) + } + } +} + +// MARK: - UNUserNotificationCenterDelegate +@available(iOS 10.0, *) +extension NotificationsController: UNUserNotificationCenterDelegate { + func userNotificationCenter(_ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: + @escaping (UNNotificationPresentationOptions) -> Void) { + // Always show the incoming notification, even if the app is in foreground + print("Received notification in foreground:") + let jsonString = notification.request.content.userInfo.jsonString ?? "{}" + print("\(jsonString)") + completionHandler([.alert, .badge, .sound]) + } + + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { + print("Received notification response") + let jsonString = response.notification.request.content.userInfo.jsonString ?? "{}" + print("\(jsonString)") + completionHandler() + } +} diff --git a/Example/Podfile b/Example/Podfile index 35d348e..682f2a4 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -52,7 +52,6 @@ target 'Messaging_Example_iOS' do platform :ios, '8.0' pod 'FirebaseMessaging' , :path => '../' - pod 'FirebaseInstanceID' target 'Messaging_Tests_iOS' do inherit! :search_paths @@ -60,6 +59,11 @@ target 'Messaging_Example_iOS' do end end +target 'Messaging_Sample_iOS' do + platform :ios, '8.0' + pod 'FirebaseMessaging' , :path => '../' +end + target 'Storage_Example_iOS' do platform :ios, '8.0' diff --git a/Example/Storage/App/iOS/FIRAppDelegate.m b/Example/Storage/App/iOS/FIRAppDelegate.m index d8e4497..9568d06 100644 --- a/Example/Storage/App/iOS/FIRAppDelegate.m +++ b/Example/Storage/App/iOS/FIRAppDelegate.m @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -@import FirebaseStorage; - #import "FIRAppDelegate.h" @implementation FIRAppDelegate -- cgit v1.2.3