Skip to content

Commit 467354a

Browse files
authored
Do Messaging's Analytics logging via Interop (#1902)
1 parent eb5ee22 commit 467354a

15 files changed

+820
-53
lines changed

Example/Firebase.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@
346346
DE26D2931F705F4D004AE1D3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE26D2071F70333E004AE1D3 /* ViewController.swift */; };
347347
DE26D2941F705F51004AE1D3 /* AuthCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1FE1F70333E004AE1D3 /* AuthCredentials.swift */; };
348348
DE26D2951F705F53004AE1D3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1FD1F70333E004AE1D3 /* AppDelegate.swift */; };
349+
DE37C63B2163D5F30025D03E /* FIRMessagingAnalyticsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE37C63A2163D5F30025D03E /* FIRMessagingAnalyticsTest.m */; };
349350
DE47C0E2207AC87D00B1AEDF /* FIRSampleAppUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = AFC8BAA31EC257D800B8EEAE /* FIRSampleAppUtilities.m */; };
350351
DE47C0E7207AC87D00B1AEDF /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
351352
DE47C114207AC94A00B1AEDF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DE47C107207AC94A00B1AEDF /* GoogleService-Info.plist */; };
@@ -1102,6 +1103,7 @@
11021103
DE26D25D1F7049F1004AE1D3 /* Auth_ApiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_ApiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
11031104
DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_EarlGreyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
11041105
DE26D27D1F705EC7004AE1D3 /* SwiftSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
1106+
DE37C63A2163D5F30025D03E /* FIRMessagingAnalyticsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRMessagingAnalyticsTest.m; sourceTree = "<group>"; };
11051107
DE45C6641E7DA8CB009E6ACD /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
11061108
DE47C0ED207AC87D00B1AEDF /* Messaging_Sample_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Messaging_Sample_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
11071109
DE47C107207AC94A00B1AEDF /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
@@ -2334,6 +2336,7 @@
23342336
DE9315D41E8738B70083EDBF /* FIRMessagingSyncMessageManagerTest.m */,
23352337
DE9315D51E8738B70083EDBF /* FIRMessagingTest.m */,
23362338
DE9315D71E8738B70083EDBF /* FIRMessagingTestNotificationUtilities.m */,
2339+
DE37C63A2163D5F30025D03E /* FIRMessagingAnalyticsTest.m */,
23372340
DE9315D81E8738B70083EDBF /* Info.plist */,
23382341
);
23392342
path = Tests;
@@ -4413,6 +4416,7 @@
44134416
DE9315FF1E8738E60083EDBF /* FIRMessagingRemoteNotificationsProxyTest.m in Sources */,
44144417
DE9315F81E8738E60083EDBF /* FIRMessagingDataMessageManagerTest.m in Sources */,
44154418
DE9316051E8738E60083EDBF /* FIRMessagingTestNotificationUtilities.m in Sources */,
4419+
DE37C63B2163D5F30025D03E /* FIRMessagingAnalyticsTest.m in Sources */,
44164420
DE9315F61E8738E60083EDBF /* FIRMessagingConnectionTest.m in Sources */,
44174421
DE9316041E8738E60083EDBF /* FIRMessagingTest.m in Sources */,
44184422
DE9315FA1E8738E60083EDBF /* FIRMessagingFakeSocket.m in Sources */,

Example/Messaging/Tests/FIRMessagingAnalyticsTest.m

Lines changed: 416 additions & 0 deletions
Large diffs are not rendered by default.

Example/Messaging/Tests/FIRMessagingLinkHandlingTest.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#import <OCMock/OCMock.h>
2020

21+
#import <FirebaseCore/FIRApp.h>
2122
#import "FIRMessaging.h"
2223
#import "FIRMessagingConstants.h"
2324
#import "FIRMessagingTestNotificationUtilities.h"
@@ -39,8 +40,7 @@ @implementation FIRMessagingLinkHandlingTest
3940

4041
- (void)setUp {
4142
[super setUp];
42-
43-
_messaging = [[FIRMessaging alloc] initPrivately];
43+
_messaging = [FIRMessaging messaging];
4444
}
4545

4646
- (void)tearDown {

Example/Messaging/Tests/FIRMessagingServiceTest.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#import "FIRMessagingTopicsCommon.h"
2626
#import "InternalHeaders/FIRMessagingInternalUtilities.h"
2727
#import "NSError+FIRMessaging.h"
28+
#import <FirebaseCore/FIRAppInternal.h>
2829

2930
static NSString *const kFakeToken =
3031
@"fE1e1PZJFSQ:APA91bFAOjp1ahBWn9rTlbjArwBEm_"

Example/Messaging/Tests/FIRMessagingTest.m

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ @interface FIRMessaging ()
3333
@property(nonatomic, readwrite, strong) FIRInstanceID *instanceID;
3434
@property(nonatomic, readwrite, strong) NSUserDefaults *messagingUserDefaults;
3535

36-
- (instancetype)initWithInstanceID:(FIRInstanceID *)instanceID
37-
userDefaults:(NSUserDefaults *)defaults;
3836
// Direct Channel Methods
3937
- (void)updateAutomaticClientConnection;
4038
- (BOOL)shouldBeConnectedAutomatically;
@@ -46,6 +44,7 @@ @interface FIRMessagingTest : XCTestCase
4644
@property(nonatomic, readonly, strong) FIRMessaging *messaging;
4745
@property(nonatomic, readwrite, strong) id mockMessaging;
4846
@property(nonatomic, readwrite, strong) id mockInstanceID;
47+
@property(nonatomic, readwrite, strong) id realInstanceID;
4948
@property(nonatomic, readwrite, strong) id mockFirebaseApp;
5049

5150
@end
@@ -54,19 +53,21 @@ @implementation FIRMessagingTest
5453

5554
- (void)setUp {
5655
[super setUp];
56+
_messaging = [FIRMessaging messaging];
5757
_mockFirebaseApp = OCMClassMock([FIRApp class]);
58-
OCMStub([_mockFirebaseApp defaultApp]).andReturn(_mockFirebaseApp);
59-
60-
_messaging = [[FIRMessaging alloc] initWithInstanceID:[FIRInstanceID instanceID]
61-
userDefaults:[NSUserDefaults standardUserDefaults]];
62-
_mockMessaging = OCMPartialMock(self.messaging);
58+
OCMStub([_mockFirebaseApp defaultApp]).andReturn(_mockFirebaseApp);
6359
_mockInstanceID = OCMPartialMock(self.messaging.instanceID);
64-
self.messaging.instanceID = _mockInstanceID;
60+
_realInstanceID = self.messaging.instanceID;
61+
self.messaging.instanceID = self.mockInstanceID;
6562
[[NSUserDefaults standardUserDefaults]
6663
removePersistentDomainForName:[NSBundle mainBundle].bundleIdentifier];
6764
}
6865

6966
- (void)tearDown {
67+
self.messaging.shouldEstablishDirectChannel = NO;
68+
self.messaging.defaultFcmToken = nil;
69+
self.messaging.instanceID = self.realInstanceID;
70+
self.messaging.apnsTokenData = nil;
7071
[_mockMessaging stopMocking];
7172
[_mockInstanceID stopMocking];
7273
[_mockFirebaseApp stopMocking];
@@ -138,7 +139,7 @@ - (void)testDoesAutomaticallyConnectIfTokenAvailableAndForegrounded {
138139
UIApplication *app = [UIApplication sharedApplication];
139140
id mockApp = OCMPartialMock(app);
140141
[[[mockApp stub] andReturnValue:@(UIApplicationStateActive)] applicationState];
141-
BOOL shouldBeConnected = [_mockMessaging shouldBeConnectedAutomatically];
142+
BOOL shouldBeConnected = [_messaging shouldBeConnectedAutomatically];
142143
XCTAssertTrue(shouldBeConnected);
143144
}
144145

@@ -155,7 +156,7 @@ - (void)testDoesNotAutomaticallyConnectIfTokenIsEmpty {
155156
UIApplication *app = [UIApplication sharedApplication];
156157
id mockApp = OCMPartialMock(app);
157158
[[[mockApp stub] andReturnValue:@(UIApplicationStateActive)] applicationState];
158-
BOOL shouldBeConnected = [_mockMessaging shouldBeConnectedAutomatically];
159+
BOOL shouldBeConnected = [_messaging shouldBeConnectedAutomatically];
159160
XCTAssertFalse(shouldBeConnected);
160161
}
161162

@@ -186,12 +187,13 @@ - (void)testAPNSTokenIncludedInOptionsIfAvailableDuringTokenFetch {
186187
[self expectationWithDescription:@"Included APNS Token data in options dict."];
187188
// Inspect the 'options' dictionary to tell whether our expectation was fulfilled
188189
[[[self.mockInstanceID stub] andDo:^(NSInvocation *invocation) {
189-
NSDictionary *options;
190-
[invocation getArgument:&options atIndex:4];
190+
NSDictionary *options;
191+
[invocation getArgument:&options atIndex:4];
191192
if (options[@"apns_token"] != nil) {
192193
[expectation fulfill];
193194
}
194195
}] tokenWithAuthorizedEntity:OCMOCK_ANY scope:OCMOCK_ANY options:OCMOCK_ANY handler:OCMOCK_ANY];
196+
self.messaging.instanceID = self.mockInstanceID;
195197
[self.messaging retrieveFCMTokenForSenderID:@"123456"
196198
completion:^(NSString * _Nullable FCMToken,
197199
NSError * _Nullable error) {}];

Firebase/Messaging/FIRMMessageCode.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,14 @@ typedef NS_ENUM(NSInteger, FIRMessagingMessageCode) {
178178
kFIRMessagingMessageCodeUtilities000 = 18000, // I-FCM018000
179179
kFIRMessagingMessageCodeUtilities001 = 18001, // I-FCM018001
180180
kFIRMessagingMessageCodeUtilities002 = 18002, // I-FCM018002
181+
// FIRMessagingAnalytics.m
182+
kFIRMessagingMessageCodeAnalytics000 = 19000, // I-FCM019000
183+
kFIRMessagingMessageCodeAnalytics001 = 19001, // I-FCM019001
184+
kFIRMessagingMessageCodeAnalytics002 = 19002, // I-FCM019002
185+
kFIRMessagingMessageCodeAnalytics003 = 19003, // I-FCM019003
186+
kFIRMessagingMessageCodeAnalytics004 = 19004, // I-FCM019004
187+
kFIRMessagingMessageCodeAnalytics005 = 19005, // I-FCM019005
188+
kFIRMessagingMessageCodeAnalyticsInvalidEvent = 19006, // I-FCM019006
189+
kFIRMessagingMessageCodeAnalytics007 = 19007, // I-FCM019007
190+
kFIRMessagingMessageCodeAnalyticsCouldNotInvokeAnalyticsLog = 19008, // I-FCM019008
181191
};

Firebase/Messaging/FIRMessaging.m

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#import <UIKit/UIKit.h>
2525

26+
#import "FIRMessagingAnalytics.h"
2627
#import "FIRMessagingClient.h"
2728
#import "FIRMessagingConstants.h"
2829
#import "FIRMessagingContextManagerService.h"
@@ -38,7 +39,13 @@
3839
#import "FIRMessagingVersionUtilities.h"
3940
#import "FIRMessaging_Private.h"
4041

42+
#import <FirebaseAnalyticsInterop/FIRAnalyticsInterop.h>
4143
#import <FirebaseCore/FIRAppInternal.h>
44+
#import <FirebaseCore/FIRComponent.h>
45+
#import <FirebaseCore/FIRComponentContainer.h>
46+
#import <FirebaseCore/FIRComponentRegistrant.h>
47+
#import <FirebaseCore/FIRCoreConfigurable.h>
48+
#import <FirebaseCore/FIRDependency.h>
4249
#import <FirebaseInstanceID/FirebaseInstanceID.h>
4350
#import <GoogleUtilities/GULReachabilityChecker.h>
4451

@@ -141,40 +148,48 @@ @interface FIRMessaging ()<FIRMessagingClientDelegate, FIRMessagingReceiverDeleg
141148
/// which can happen if the user inadvertently calls `appDidReceiveMessage` along with us
142149
/// calling it implicitly during swizzling.
143150
@property(nonatomic, readwrite, strong) NSMutableSet *loggedMessageIDs;
151+
@property(nonatomic, readwrite, strong) id<FIRAnalyticsInterop> _Nullable analytics;
144152

145-
- (instancetype)initWithInstanceID:(FIRInstanceID *)instanceID
146-
userDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER;
153+
@end
154+
155+
// Messaging doesn't provide any functionality to other components,
156+
// so it provides a private, empty protocol that it conforms to and use it for registration.
157+
158+
@protocol FIRMessagingInstanceProvider
159+
@end
147160

161+
@interface FIRMessaging () <FIRMessagingInstanceProvider,
162+
FIRCoreConfigurable,
163+
FIRComponentRegistrant>
148164
@end
149165

150166
@implementation FIRMessaging
151167

152168
+ (FIRMessaging *)messaging {
153-
static FIRMessaging *messaging;
169+
FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here.
170+
id<FIRMessagingInstanceProvider> messaging =
171+
FIR_COMPONENT(FIRMessagingInstanceProvider, defaultApp.container);
172+
154173
static dispatch_once_t onceToken;
155174
dispatch_once(&onceToken, ^{
156-
messaging = [[FIRMessaging alloc] initPrivately];
157-
[messaging start];
175+
[(FIRMessaging *)messaging start];
158176
});
159-
return messaging;
177+
return (FIRMessaging *)messaging;
160178
}
161179

162-
- (instancetype)initWithInstanceID:(FIRInstanceID *)instanceID
163-
userDefaults:(NSUserDefaults *)defaults {
180+
- (instancetype)initWithAnalytics:(nullable id<FIRAnalyticsInterop>)analytics
181+
withInstanceID:(FIRInstanceID *)instanceID
182+
withUserDefaults:(NSUserDefaults *)defaults {
164183
self = [super init];
165184
if (self != nil) {
166185
_loggedMessageIDs = [NSMutableSet set];
167186
_instanceID = instanceID;
168187
_messagingUserDefaults = defaults;
188+
_analytics = analytics;
169189
}
170190
return self;
171191
}
172192

173-
- (instancetype)initPrivately {
174-
return [self initWithInstanceID:[FIRInstanceID instanceID]
175-
userDefaults:[NSUserDefaults standardUserDefaults]];
176-
}
177-
178193
- (void)dealloc {
179194
[self.reachability stop];
180195
[[NSNotificationCenter defaultCenter] removeObserver:self];
@@ -184,24 +199,38 @@ - (void)dealloc {
184199
#pragma mark - Config
185200

186201
+ (void)load {
187-
[[NSNotificationCenter defaultCenter] addObserver:self
188-
selector:@selector(didReceiveConfigureSDKNotification:)
189-
name:kFIRAppReadyToConfigureSDKNotification
190-
object:nil];
202+
[FIRApp registerAsConfigurable:self];
203+
[FIRComponentContainer registerAsComponentRegistrant:self];
204+
}
205+
206+
+ (nonnull NSArray<FIRComponent *> *)componentsToRegister {
207+
FIRDependency *analyticsDep =
208+
[FIRDependency dependencyWithProtocol:@protocol(FIRAnalyticsInterop) isRequired:NO];
209+
FIRComponentCreationBlock creationBlock =
210+
^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {
211+
// Ensure it's cached so it returns the same instance every time messaging is called.
212+
*isCacheable = YES;
213+
id<FIRAnalyticsInterop> analytics = FIR_COMPONENT(FIRAnalyticsInterop, container);
214+
return [[FIRMessaging alloc] initWithAnalytics:analytics
215+
withInstanceID:[FIRInstanceID instanceID]
216+
withUserDefaults:[NSUserDefaults standardUserDefaults]];
217+
};
218+
FIRComponent *messagingProvider =
219+
[FIRComponent componentWithProtocol:@protocol(FIRMessagingInstanceProvider)
220+
instantiationTiming:FIRInstantiationTimingLazy
221+
dependencies:@[ analyticsDep ]
222+
creationBlock:creationBlock];
223+
224+
return @[ messagingProvider ];
191225
}
192226

193-
+ (void)didReceiveConfigureSDKNotification:(NSNotification *)notification {
194-
NSDictionary *appInfoDict = notification.userInfo;
195-
NSNumber *isDefaultApp = appInfoDict[kFIRAppIsDefaultAppKey];
196-
if (![isDefaultApp boolValue]) {
227+
+ (void)configureWithApp:(FIRApp *)app {
228+
if (!app.isDefaultApp) {
197229
// Only configure for the default FIRApp.
198230
FIRMessagingLoggerDebug(kFIRMessagingMessageCodeFIRApp001,
199231
@"Firebase Messaging only works with the default app.");
200232
return;
201233
}
202-
203-
NSString *appName = appInfoDict[kFIRAppNameKey];
204-
FIRApp *app = [FIRApp appNamed:appName];
205234
[[FIRMessaging messaging] configureMessaging:app];
206235
}
207236

@@ -367,16 +396,7 @@ - (FIRMessagingMessageInfo *)appDidReceiveMessage:(NSDictionary *)message {
367396
}
368397

369398
if (!isOldMessage) {
370-
Class firMessagingLogClass = NSClassFromString(@"FIRMessagingLog");
371-
SEL logMessageSelector = NSSelectorFromString(@"logMessage:");
372-
373-
if ([firMessagingLogClass respondsToSelector:logMessageSelector]) {
374-
#pragma clang diagnostic push
375-
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
376-
[firMessagingLogClass performSelector:logMessageSelector
377-
withObject:message];
378-
}
379-
#pragma clang diagnostic pop
399+
[FIRMessagingAnalytics logMessage:message toAnalytics:_analytics];
380400
[self handleContextManagerMessage:message];
381401
[self handleIncomingLinkIfNeededFromMessage:message];
382402
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <Foundation/Foundation.h>
18+
19+
#import <FirebaseAnalyticsInterop/FIRAnalyticsInterop.h>
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
/**
24+
* Provides integration between FIRMessaging and Analytics.
25+
*
26+
* All Analytics dependencies should be kept in this class, and missing dependencies should be
27+
* handled gracefully.
28+
*
29+
*/
30+
@interface FIRMessagingAnalytics : NSObject
31+
32+
/**
33+
* Determine whether a notification has the properties to be loggable to Analytics.
34+
* If so, send the notification.
35+
* @param notification The notification payload from APNs
36+
* @param analytics The class to be used as the receiver of the logging method
37+
*/
38+
39+
+ (void)logMessage:(NSDictionary *)notification
40+
toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics;
41+
42+
@end
43+
44+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)