Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion FirebaseFunctions.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Cloud Functions for Firebase.
'Functions/FirebaseFunctions/**/*',
'Interop/Auth/Public/*.h',
'FirebaseCore/Sources/Private/*.h',
'FirebaseMessaging/Sources/Interop/FIRMessagingInterop.h',
]
s.public_header_files = 'Functions/FirebaseFunctions/Public/FirebaseFunctions/*.h'

Expand All @@ -40,13 +41,18 @@ Cloud Functions for Firebase.
}

s.test_spec 'unit' do |unit_tests|
unit_tests.source_files = 'Functions/Example/Test*/*.[mh]', 'SharedTestUtilities/FIRAuthInteropFake*'
unit_tests.source_files = [
'Functions/Example/Test*/*.[mh]',
'SharedTestUtilities/FIRAuthInteropFake*',
'SharedTestUtilities/FIRMessagingInteropFake*',
]
end

s.test_spec 'integration' do |int_tests|
int_tests.source_files = 'Functions/Example/IntegrationTests/*.[mh]',
'Functions/Example/TestUtils/*.[mh]',
'SharedTestUtilities/FIRAuthInteropFake*',
'SharedTestUtilities/FIRMessagingInteropFake*',
'Functions/Example/GoogleService-Info.plist'
end
end
14 changes: 4 additions & 10 deletions FirebaseMessaging/Sources/FIRMessaging.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import <FirebaseMessaging/FIRMessaging.h>
#import <FirebaseMessaging/FIRMessagingExtensionHelper.h>
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
#import "FirebaseMessaging/Sources/Interop/FIRMessagingInterop.h"
#import "GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h"
#import "GoogleUtilities/Reachability/Private/GULReachabilityChecker.h"
#import "GoogleUtilities/UserDefaults/Private/GULUserDefaults.h"
Expand Down Expand Up @@ -161,21 +162,14 @@ @interface FIRMessaging () <FIRMessagingClientDelegate,

@end

// Messaging doesn't provide any functionality to other components,
// so it provides a private, empty protocol that it conforms to and use it for registration.

@protocol FIRMessagingInstanceProvider
@end

@interface FIRMessaging () <FIRMessagingInstanceProvider, FIRLibrary>
@interface FIRMessaging () <FIRMessagingInterop, FIRLibrary>
@end

@implementation FIRMessaging

+ (FIRMessaging *)messaging {
FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here.
id<FIRMessagingInstanceProvider> instance =
FIR_COMPONENT(FIRMessagingInstanceProvider, defaultApp.container);
id<FIRMessagingInterop> instance = FIR_COMPONENT(FIRMessagingInterop, defaultApp.container);

// We know the instance coming from the container is a FIRMessaging instance, cast it and move on.
return (FIRMessaging *)instance;
Expand Down Expand Up @@ -241,7 +235,7 @@ + (void)load {
return messaging;
};
FIRComponent *messagingProvider =
[FIRComponent componentWithProtocol:@protocol(FIRMessagingInstanceProvider)
[FIRComponent componentWithProtocol:@protocol(FIRMessagingInterop)
instantiationTiming:FIRInstantiationTimingEagerInDefaultApp
dependencies:@[ analyticsDep ]
creationBlock:creationBlock];
Expand Down
41 changes: 41 additions & 0 deletions FirebaseMessaging/Sources/Interop/FIRMessagingInterop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2020 Google LLC
*
* 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/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

/** Connector for bridging communication between Firebase SDKs and FIRMessaging API. */
@protocol FIRMessagingInterop <NSObject>

/**
* The FCM registration token is used to identify this device so that FCM can send notifications to
* it. It is associated with your APNs token when the APNs token is supplied, so messages sent to
* the FCM token will be delivered over APNs.
*
* The FCM registration token is sometimes refreshed automatically. In your FIRMessaging delegate,
* the delegate method `messaging:didReceiveRegistrationToken:` will be called once a token is
* available, or has been refreshed. Typically it should be called once per app start, but
* may be called more often if the token is invalidated or updated.
*
* Once you have an FCM registration token, you should send it to your application server, so it can
* use the FCM token to send notifications to your device.
*/
@property(nonatomic, readonly, nullable) NSString *FCMToken NS_SWIFT_NAME(fcmToken);

@end

NS_ASSUME_NONNULL_END
4 changes: 2 additions & 2 deletions Functions/Backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ exports.tokenTest = functions.https.onRequest((request, response) => {
response.send({ data: {} });
});

exports.instanceIdTest = functions.https.onRequest((request, response) => {
assert.equal(request.get('Firebase-Instance-ID-Token'), 'iid');
exports.FCMTokenTest = functions.https.onRequest((request, response) => {
assert.equal(request.get('Firebase-Instance-ID-Token'), 'fakeFCMToken');
assert.deepEqual(request.body, { data: {} });
response.send({ data: {} });
});
Expand Down
2 changes: 1 addition & 1 deletion Functions/Backend/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ FUNCTIONS_BIN="./node_modules/.bin/functions"
"${FUNCTIONS_BIN}" deploy dataTest --trigger-http
"${FUNCTIONS_BIN}" deploy scalarTest --trigger-http
"${FUNCTIONS_BIN}" deploy tokenTest --trigger-http
"${FUNCTIONS_BIN}" deploy instanceIdTest --trigger-http
"${FUNCTIONS_BIN}" deploy FCMTokenTest --trigger-http
"${FUNCTIONS_BIN}" deploy nullTest --trigger-http
"${FUNCTIONS_BIN}" deploy missingResultTest --trigger-http
"${FUNCTIONS_BIN}" deploy unhandledErrorTest --trigger-http
Expand Down
3 changes: 3 additions & 0 deletions Functions/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# v2.8.0
- [changed] Weak dependency on Instance ID replaced by Firebase Messaging. (#6395)

# v2.7.0
- [changed] Functionally neutral source reorganization. (#5858)

Expand Down
15 changes: 10 additions & 5 deletions Functions/Example/IntegrationTests/FIRIntegrationTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"

#import "FIRAuthInteropFake.h"
#import "Functions/Example/TestUtils/FUNFakeInstanceID.h"
#import "Functions/FirebaseFunctions/FIRFunctions+Internal.h"
#import "Functions/FirebaseFunctions/Public/FirebaseFunctions/FIRError.h"
#import "Functions/FirebaseFunctions/Public/FirebaseFunctions/FIRFunctions.h"
#import "Functions/FirebaseFunctions/Public/FirebaseFunctions/FIRHTTPSCallable.h"
#import "SharedTestUtilities/FIRMessagingInteropFake.h"

// Project ID used by these tests.
static NSString *const kDefaultProjectID = @"functions-integration-test";
Expand All @@ -30,6 +30,7 @@ @interface FIRIntegrationTests : XCTestCase {
FIRFunctions *_functions;
NSString *_projectID;
BOOL _useLocalhost;
FIRMessagingInteropFake *_messagingFake;
}
@end

Expand All @@ -38,6 +39,8 @@ @implementation FIRIntegrationTests
- (void)setUp {
[super setUp];

_messagingFake = [[FIRMessagingInteropFake alloc] init];

_projectID = kDefaultProjectID;
_useLocalhost = YES;

Expand All @@ -51,7 +54,8 @@ - (void)setUp {
_functions = [[FIRFunctions alloc]
initWithProjectID:_projectID
region:@"us-central1"
auth:[[FIRAuthInteropFake alloc] initWithToken:nil userID:nil error:nil]];
auth:[[FIRAuthInteropFake alloc] initWithToken:nil userID:nil error:nil]
messaging:_messagingFake];
if (_useLocalhost) {
[_functions useLocalhost];
}
Expand Down Expand Up @@ -101,7 +105,8 @@ - (void)testToken {
FIRFunctions *functions = [[FIRFunctions alloc]
initWithProjectID:_projectID
region:@"us-central1"
auth:[[FIRAuthInteropFake alloc] initWithToken:@"token" userID:nil error:nil]];
auth:[[FIRAuthInteropFake alloc] initWithToken:@"token" userID:nil error:nil]
messaging:_messagingFake];
if (_useLocalhost) {
[functions useLocalhost];
}
Expand All @@ -117,9 +122,9 @@ - (void)testToken {
[self waitForExpectations:@[ expectation ] timeout:10];
}

- (void)testInstanceID {
- (void)testFCMToken {
XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"instanceIdTest"];
FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"FCMTokenTest"];
[function callWithObject:@{}
completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
XCTAssertNil(error);
Expand Down
3 changes: 2 additions & 1 deletion Functions/Example/Tests/FIRFunctionsTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ - (void)tearDown {
- (void)testURLWithName {
FIRFunctions *functions = [[FIRFunctions alloc] initWithProjectID:@"my-project"
region:@"my-region"
auth:nil];
auth:nil
messaging:nil];
NSString *url = [functions URLWithName:@"my-endpoint"];
XCTAssertEqualObjects(@"https://my-region-my-project.cloudfunctions.net/my-endpoint", url);
}
Expand Down
18 changes: 13 additions & 5 deletions Functions/Example/Tests/FUNContextProviderTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,29 @@

#import "FIRAuthInteropFake.h"
#import "Functions/FirebaseFunctions/FUNContext.h"
#import "SharedTestUtilities/FIRMessagingInteropFake.h"

@interface FUNContextProviderTests : XCTestCase
@property(nonatomic) FIRMessagingInteropFake *messagingFake;
@end

@implementation FUNContextProviderTests

- (void)setUp {
self.messagingFake = [[FIRMessagingInteropFake alloc] init];
}

- (void)testContextWithAuth {
FIRAuthInteropFake *auth = [[FIRAuthInteropFake alloc] initWithToken:@"token"
userID:@"userID"
error:nil];
FUNContextProvider *provider = [[FUNContextProvider alloc] initWithAuth:(id<FIRAuthInterop>)auth];
FUNContextProvider *provider = [[FUNContextProvider alloc] initWithAuth:(id<FIRAuthInterop>)auth
messaging:self.messagingFake];
XCTestExpectation *expectation =
[self expectationWithDescription:@"Context should have auth keys."];
[provider getContext:^(FUNContext *_Nullable context, NSError *_Nullable error) {
XCTAssert([context.authToken isEqualToString:@"token"]);
XCTAssert([context.instanceIDToken isEqualToString:@"iid"]);
XCTAssert([context.FCMToken isEqualToString:self.messagingFake.FCMToken]);
XCTAssertNil(error);
[expectation fulfill];
}];
Expand All @@ -44,7 +51,8 @@ - (void)testContextWithAuthError {
FIRAuthInteropFake *auth = [[FIRAuthInteropFake alloc] initWithToken:nil
userID:nil
error:authError];
FUNContextProvider *provider = [[FUNContextProvider alloc] initWithAuth:(id<FIRAuthInterop>)auth];
FUNContextProvider *provider = [[FUNContextProvider alloc] initWithAuth:(id<FIRAuthInterop>)auth
messaging:self.messagingFake];
XCTestExpectation *expectation =
[self expectationWithDescription:@"Completion handler should fail with Auth error."];
[provider getContext:^(FUNContext *_Nullable context, NSError *_Nullable error) {
Expand All @@ -57,13 +65,13 @@ - (void)testContextWithAuthError {
}

- (void)testContextWithoutAuth {
FUNContextProvider *provider = [[FUNContextProvider alloc] initWithAuth:nil];
FUNContextProvider *provider = [[FUNContextProvider alloc] initWithAuth:nil messaging:nil];
XCTestExpectation *expectation =
[self expectationWithDescription:@"Completion handler should succeed without Auth."];
[provider getContext:^(FUNContext *_Nullable context, NSError *_Nullable error) {
XCTAssertNil(error);
XCTAssertNil(context.authToken);
XCTAssert([context.instanceIDToken isEqualToString:@"iid"]);
XCTAssertNil(context.FCMToken);
[expectation fulfill];
}];

Expand Down
5 changes: 4 additions & 1 deletion Functions/FirebaseFunctions/FIRFunctions+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import "Functions/FirebaseFunctions/Public/FirebaseFunctions/FIRFunctions.h"

@protocol FIRAuthInterop;
@protocol FIRMessagingInterop;
@class FIRHTTPSCallableResult;

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -52,10 +53,12 @@ NS_ASSUME_NONNULL_BEGIN
* @param projectID The project ID for the Firebase project.
* @param region The region for the http trigger, such as "us-central1".
* @param auth The auth provider to use (optional).
* @param messaging The messaging interop to use (optional).
*/
- (id)initWithProjectID:(NSString *)projectID
region:(NSString *)region
auth:(nullable id<FIRAuthInterop>)auth;
auth:(nullable id<FIRAuthInterop>)auth
messaging:(nullable id<FIRMessagingInterop>)messaging;

@end

Expand Down
19 changes: 12 additions & 7 deletions Functions/FirebaseFunctions/FIRFunctions.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#import "Functions/FirebaseFunctions/FIRFunctions+Internal.h"

#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
#import "FirebaseMessaging/Sources/Interop/FIRMessagingInterop.h"
#import "Interop/Auth/Public/FIRAuthInterop.h"

#import "Functions/FirebaseFunctions/FIRHTTPSCallable+Internal.h"
Expand All @@ -41,7 +42,7 @@

NS_ASSUME_NONNULL_BEGIN

NSString *const kFUNInstanceIDTokenHeader = @"Firebase-Instance-ID-Token";
NSString *const kFUNFCMTokenHeader = @"Firebase-Instance-ID-Token";
NSString *const kFUNDefaultRegion = @"us-central1";

/// Empty protocol to register Functions as a component with Core.
Expand All @@ -66,7 +67,9 @@ @interface FIRFunctions () <FIRLibrary, FIRFunctionsInstanceProvider> {
// Re-declare this initializer here in order to attribute it as the designated initializer.
- (instancetype)initWithProjectID:(NSString *)projectID
region:(NSString *)region
auth:(nullable id<FIRAuthInterop>)auth NS_DESIGNATED_INITIALIZER;
auth:(nullable id<FIRAuthInterop>)auth
messaging:(nullable id<FIRMessagingInterop>)messaging
NS_DESIGNATED_INITIALIZER;

@end

Expand Down Expand Up @@ -112,12 +115,14 @@ + (instancetype)functionsForApp:(FIRApp *)app region:(NSString *)region {
- (instancetype)initWithApp:(FIRApp *)app region:(NSString *)region {
return [self initWithProjectID:app.options.projectID
region:region
auth:FIR_COMPONENT(FIRAuthInterop, app.container)];
auth:FIR_COMPONENT(FIRAuthInterop, app.container)
messaging:FIR_COMPONENT(FIRMessagingInterop, app.container)];
}

- (instancetype)initWithProjectID:(NSString *)projectID
region:(NSString *)region
auth:(nullable id<FIRAuthInterop>)auth {
auth:(nullable id<FIRAuthInterop>)auth
messaging:(nullable id<FIRMessagingInterop>)messaging {
self = [super init];
if (self) {
if (!region) {
Expand All @@ -127,7 +132,7 @@ - (instancetype)initWithProjectID:(NSString *)projectID
_projectID = [projectID copy];
_region = [region copy];
_serializer = [[FUNSerializer alloc] init];
_contextProvider = [[FUNContextProvider alloc] initWithAuth:auth];
_contextProvider = [[FUNContextProvider alloc] initWithAuth:auth messaging:messaging];
_emulatorOrigin = nil;
}
return self;
Expand Down Expand Up @@ -216,8 +221,8 @@ - (void)callFunction:(NSString *)name
NSString *value = [NSString stringWithFormat:@"Bearer %@", context.authToken];
[fetcher setRequestValue:value forHTTPHeaderField:@"Authorization"];
}
if (context.instanceIDToken) {
[fetcher setRequestValue:context.instanceIDToken forHTTPHeaderField:kFUNInstanceIDTokenHeader];
if (context.FCMToken) {
[fetcher setRequestValue:context.FCMToken forHTTPHeaderField:kFUNFCMTokenHeader];
}

// Override normal security rules if this is a local test.
Expand Down
7 changes: 5 additions & 2 deletions Functions/FirebaseFunctions/FUNContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#import <Foundation/Foundation.h>

@class FIRApp;

@protocol FIRAuthInterop;
@protocol FIRMessagingInterop;

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -26,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface FUNContext : NSObject
- (id)init NS_UNAVAILABLE;
@property(nonatomic, copy, nullable, readonly) NSString *authToken;
@property(nonatomic, copy, nullable, readonly) NSString *instanceIDToken;
@property(nonatomic, copy, nullable, readonly) NSString *FCMToken;
@end

/**
Expand All @@ -36,7 +38,8 @@ NS_ASSUME_NONNULL_BEGIN

- (id)init NS_UNAVAILABLE;

- (instancetype)initWithAuth:(nullable id<FIRAuthInterop>)auth NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithAuth:(nullable id<FIRAuthInterop>)auth
messaging:(nullable id<FIRMessagingInterop>)messaging NS_DESIGNATED_INITIALIZER;

- (void)getContext:(void (^)(FUNContext *_Nullable context, NSError *_Nullable error))completion;

Expand Down
Loading