aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2018-03-20 15:41:44 -0700
committerGravatar GitHub <noreply@github.com>2018-03-20 15:41:44 -0700
commit87e511d52ad400e0a44a60c62325b2fd213930a3 (patch)
tree16bc6ef0777ded7f939145ba537b1b9fac6c938f
parent529666594951b86604730a8b400f71d7eedd1e85 (diff)
parent03275eb249946d2f8388e130011831e4bbd17d91 (diff)
Merge pull request #950 from firebase/release-4.11.0
Release 4.11.0
-rw-r--r--Example/Auth/Sample/MainViewController.m30
-rw-r--r--Example/Podfile2
-rw-r--r--Firebase/Auth/Source/FIRAuth.m4
-rw-r--r--Firebase/Auth/Source/FIRAuthProvider.m25
-rw-r--r--Firebase/Auth/Source/Public/FIREmailAuthProvider.h11
-rw-r--r--Firebase/Auth/Source/Public/FIRFacebookAuthProvider.h5
-rw-r--r--Firebase/Auth/Source/Public/FIRGitHubAuthProvider.h6
-rw-r--r--Firebase/Auth/Source/Public/FIRGoogleAuthProvider.h5
-rw-r--r--Firebase/Auth/Source/Public/FIRPhoneAuthProvider.h6
-rw-r--r--Firebase/Auth/Source/Public/FIRTwitterAuthProvider.h6
-rw-r--r--Firebase/Core/FIROptions.m2
-rw-r--r--FirebaseAuth.podspec2
-rw-r--r--FirebaseCore.podspec2
-rw-r--r--FirebaseFirestore.podspec2
-rw-r--r--FirebaseFunctions.podspec33
-rw-r--r--Firestore/Example/Podfile2
-rw-r--r--Firestore/Source/Util/FSTDispatchQueue.mm7
-rw-r--r--Functions/.clang-format7
-rw-r--r--Functions/Backend/index.js95
-rw-r--r--Functions/Backend/package.json12
-rwxr-xr-xFunctions/Backend/start.sh55
-rw-r--r--Functions/CHANGELOG.md2
-rw-r--r--Functions/Example/FirebaseFunctions.xcodeproj/project.pbxproj848
-rw-r--r--Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions-Example.xcscheme113
-rw-r--r--Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_IntegrationTests.xcscheme56
-rw-r--r--Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_Tests.xcscheme56
-rw-r--r--Functions/Example/FirebaseFunctions/Base.lproj/LaunchScreen.storyboard27
-rw-r--r--Functions/Example/FirebaseFunctions/Base.lproj/Main.storyboard27
-rw-r--r--Functions/Example/FirebaseFunctions/FIRAppDelegate.h21
-rw-r--r--Functions/Example/FirebaseFunctions/FIRAppDelegate.m55
-rw-r--r--Functions/Example/FirebaseFunctions/FIRViewController.h19
-rw-r--r--Functions/Example/FirebaseFunctions/FIRViewController.m33
-rw-r--r--Functions/Example/FirebaseFunctions/FirebaseFunctions-Info.plist54
-rw-r--r--Functions/Example/FirebaseFunctions/Images.xcassets/AppIcon.appiconset/Contents.json93
-rw-r--r--Functions/Example/FirebaseFunctions/en.lproj/InfoPlist.strings2
-rw-r--r--Functions/Example/FirebaseFunctions/main.m22
-rw-r--r--Functions/Example/IntegrationTests/FIRIntegrationTests.m190
-rw-r--r--Functions/Example/IntegrationTests/IntegrationTests-Info.plist22
-rw-r--r--Functions/Example/Podfile16
-rw-r--r--Functions/Example/TestUtils/FUNFakeApp.h39
-rw-r--r--Functions/Example/TestUtils/FUNFakeApp.m71
-rw-r--r--Functions/Example/TestUtils/FUNFakeInstanceID.h34
-rw-r--r--Functions/Example/TestUtils/FUNFakeInstanceID.m33
-rw-r--r--Functions/Example/Tests/FIRFunctionsTests.m50
-rw-r--r--Functions/Example/Tests/FUNSerializerTests.m240
-rw-r--r--Functions/Example/Tests/Tests-Info.plist22
-rw-r--r--Functions/Example/Tests/en.lproj/InfoPlist.strings2
-rw-r--r--Functions/FirebaseFunctions/FIRFunctions+Internal.h50
-rw-r--r--Functions/FirebaseFunctions/FIRFunctions.m247
-rw-r--r--Functions/FirebaseFunctions/FIRHTTPSCallable+Internal.h46
-rw-r--r--Functions/FirebaseFunctions/FIRHTTPSCallable.m71
-rw-r--r--Functions/FirebaseFunctions/FUNContext.h44
-rw-r--r--Functions/FirebaseFunctions/FUNContext.m87
-rw-r--r--Functions/FirebaseFunctions/FUNError.h34
-rw-r--r--Functions/FirebaseFunctions/FUNError.m189
-rw-r--r--Functions/FirebaseFunctions/FUNInstanceIDProxy.h29
-rw-r--r--Functions/FirebaseFunctions/FUNInstanceIDProxy.m57
-rw-r--r--Functions/FirebaseFunctions/FUNSerializer.h33
-rw-r--r--Functions/FirebaseFunctions/FUNSerializer.m231
-rw-r--r--Functions/FirebaseFunctions/FUNUsageValidation.h38
-rw-r--r--Functions/FirebaseFunctions/FUNUsageValidation.m28
-rw-r--r--Functions/FirebaseFunctions/Public/FIRError.h91
-rw-r--r--Functions/FirebaseFunctions/Public/FIRFunctions.h66
-rw-r--r--Functions/FirebaseFunctions/Public/FIRHTTPSCallable.h93
-rw-r--r--Functions/README.md21
-rw-r--r--README.md14
66 files changed, 3919 insertions, 16 deletions
diff --git a/Example/Auth/Sample/MainViewController.m b/Example/Auth/Sample/MainViewController.m
index 36ef92d..f6893d1 100644
--- a/Example/Auth/Sample/MainViewController.m
+++ b/Example/Auth/Sample/MainViewController.m
@@ -96,6 +96,11 @@ static NSString *const kSignInGoogleButtonText = @"Sign in with Google";
*/
static NSString *const kSignInWithEmailLink = @"Sign in with Email Link";
+/** @var kVerifyEmailLinkAccount
+ @brief The text of the "Verify Email-link Account" button.
+ */
+static NSString *const kVerifyEmailLinkAccount = @"Verify Email-link Account";
+
/** @var kSendEmailSignInLink
@brief The text of the "Send Email SignIn link" button
*/
@@ -739,6 +744,8 @@ typedef enum {
action:^{ [weakSelf signInGoogle]; }],
[StaticContentTableViewCell cellWithTitle:kSignInWithEmailLink
action:^{ [weakSelf signInWithEmailLink]; }],
+ [StaticContentTableViewCell cellWithTitle:kVerifyEmailLinkAccount
+ action:^{ [weakSelf verifyEmailLinkAccount]; }],
[StaticContentTableViewCell cellWithTitle:kSendEmailSignInLink
action:^{ [weakSelf sendEmailSignInLink]; }],
[StaticContentTableViewCell cellWithTitle:kSignInGoogleAndRetrieveDataButtonText
@@ -1784,6 +1791,29 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
}];
}
+/** @fn verifyEmailLinkAccount
+ @brief Invoked to verify that the current user is an email-link user.
+ */
+- (void)verifyEmailLinkAccount {
+ if (![FIRAuth auth].currentUser.email) {
+ [self showMessagePrompt:@"There is no signed-in user available."];
+ return;
+ }
+ [[FIRAuth auth] fetchSignInMethodsForEmail:[FIRAuth auth].currentUser.email
+ completion:^(NSArray<NSString *> *_Nullable signInMethods,
+ NSError *_Nullable error) {
+ if (error) {
+ [self showMessagePrompt:@"There was an error fetching sign-in methods."];
+ return;
+ }
+ if (![signInMethods containsObject:FIREmailLinkAuthSignInMethod]) {
+ [self showMessagePrompt:@"Error: The current user is NOT an email-link user."];
+ return;
+ }
+ [self showMessagePrompt:@"The current user is an email-link user."];
+ }];
+}
+
/** @fn sendEmailSignInLink
@brief Invoked when "Send email sign-in link" row is pressed.
*/
diff --git a/Example/Podfile b/Example/Podfile
index f216308..35d348e 100644
--- a/Example/Podfile
+++ b/Example/Podfile
@@ -8,7 +8,7 @@ target 'Core_Example_iOS' do
# The next line is the forcing function for the Firebase pod. The Firebase
# version's subspecs should depend on the component versions in their
# corresponding podspec's.
- pod 'Firebase/Core', '4.10.1'
+ pod 'Firebase/Core', '4.11.0'
target 'Core_Tests_iOS' do
inherit! :search_paths
diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m
index 3b29238..dc3154f 100644
--- a/Firebase/Auth/Source/FIRAuth.m
+++ b/Firebase/Auth/Source/FIRAuth.m
@@ -533,7 +533,7 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
FIRCreateAuthURIRequest *request =
[[FIRCreateAuthURIRequest alloc] initWithIdentifier:email
continueURI:@"http://www.google.com/"
- requestConfiguration:_requestConfiguration];
+ requestConfiguration:self->_requestConfiguration];
[FIRAuthBackend createAuthURI:request callback:^(FIRCreateAuthURIResponse *_Nullable response,
NSError *_Nullable error) {
if (completion) {
@@ -1124,7 +1124,7 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
FIRGetOOBConfirmationCodeRequest *request =
[FIRGetOOBConfirmationCodeRequest signInWithEmailLinkRequest:email
actionCodeSettings:actionCodeSettings
- requestConfiguration:_requestConfiguration];
+ requestConfiguration:self->_requestConfiguration];
[FIRAuthBackend getOOBConfirmationCode:request
callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response,
NSError *_Nullable error) {
diff --git a/Firebase/Auth/Source/FIRAuthProvider.m b/Firebase/Auth/Source/FIRAuthProvider.m
index 6df86d7..72a00ef 100644
--- a/Firebase/Auth/Source/FIRAuthProvider.m
+++ b/Firebase/Auth/Source/FIRAuthProvider.m
@@ -16,6 +16,8 @@
#import <Foundation/Foundation.h>
+#pragma mark - Provider ID constants
+
// Declared 'extern' in FIRGoogleAuthProvider.h
NSString *const FIRGoogleAuthProviderID = @"google.com";
@@ -36,3 +38,26 @@ NSString *const FIRGitHubAuthProviderID = @"github.com";
// Declared 'extern' in FIRPhoneAuthProvider.h
NSString *const FIRPhoneAuthProviderID = @"phone";
+
+#pragma mark - sign-in methods constants
+
+// Declared 'extern' in FIRGoogleAuthProvider.h
+NSString *const FIRGoogleAuthSignInMethod = @"google.com";
+
+// Declared 'extern' in FIREmailAuthProvider.h
+NSString *const FIREmailPasswordAuthSignInMethod = @"password";
+
+// Declared 'extern' in FIREmailAuthProvider.h
+NSString *const FIREmailLinkAuthSignInMethod = @"emailLink";
+
+// Declared 'extern' in FIRTwitterAuthProvider.h
+NSString *const FIRTwitterAuthSignInMethod = @"twitter.com";
+
+// Declared 'extern' in FIRFacebookAuthProvider.h
+NSString *const FIRFacebookAuthSignInMethod = @"facebook.com";
+
+// Declared 'extern' in FIRGitHubAuthProvider.h
+NSString *const FIRGitHubAuthSignInMethod = @"github.com";
+
+// Declared 'extern' in FIRPhoneAuthProvider.h
+NSString *const FIRPhoneAuthSignInMethod = @"phone";
diff --git a/Firebase/Auth/Source/Public/FIREmailAuthProvider.h b/Firebase/Auth/Source/Public/FIREmailAuthProvider.h
index 5823911..b6375bd 100644
--- a/Firebase/Auth/Source/Public/FIREmailAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIREmailAuthProvider.h
@@ -26,6 +26,17 @@ NS_ASSUME_NONNULL_BEGIN
extern NSString *const FIREmailAuthProviderID NS_SWIFT_NAME(EmailAuthProviderID);
/**
+ @brief A string constant identifying the email-link sign-in method.
+ */
+extern NSString *const FIREmailLinkAuthSignInMethod NS_SWIFT_NAME(EmailLinkAuthSignInMethod);
+
+/**
+ @brief A string constant identifying the email & password sign-in method.
+ */
+extern NSString *const FIREmailPasswordAuthSignInMethod
+ NS_SWIFT_NAME(EmailPasswordAuthSignInMethod);
+
+/**
@brief Please use `FIREmailAuthProviderID` for Objective-C or `EmailAuthProviderID` for Swift instead.
*/
extern NSString *const FIREmailPasswordAuthProviderID __attribute__((deprecated));
diff --git a/Firebase/Auth/Source/Public/FIRFacebookAuthProvider.h b/Firebase/Auth/Source/Public/FIRFacebookAuthProvider.h
index f08740f..75efe13 100644
--- a/Firebase/Auth/Source/Public/FIRFacebookAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIRFacebookAuthProvider.h
@@ -25,6 +25,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
extern NSString *const FIRFacebookAuthProviderID NS_SWIFT_NAME(FacebookAuthProviderID);
+/**
+ @brief A string constant identifying the Facebook sign-in method.
+ */
+extern NSString *const _Nonnull FIRFacebookAuthSignInMethod NS_SWIFT_NAME(FacebookAuthSignInMethod);
+
/** @class FIRFacebookAuthProvider
@brief Utility class for constructing Facebook credentials.
*/
diff --git a/Firebase/Auth/Source/Public/FIRGitHubAuthProvider.h b/Firebase/Auth/Source/Public/FIRGitHubAuthProvider.h
index f0b5dbe..0610427 100644
--- a/Firebase/Auth/Source/Public/FIRGitHubAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIRGitHubAuthProvider.h
@@ -25,6 +25,12 @@ NS_ASSUME_NONNULL_BEGIN
*/
extern NSString *const FIRGitHubAuthProviderID NS_SWIFT_NAME(GitHubAuthProviderID);
+/**
+ @brief A string constant identifying the GitHub sign-in method.
+ */
+extern NSString *const _Nonnull FIRGitHubAuthSignInMethod NS_SWIFT_NAME(GitHubAuthSignInMethod);
+
+
/** @class FIRGitHubAuthProvider
@brief Utility class for constructing GitHub credentials.
*/
diff --git a/Firebase/Auth/Source/Public/FIRGoogleAuthProvider.h b/Firebase/Auth/Source/Public/FIRGoogleAuthProvider.h
index e80d87e..7d6fa22 100644
--- a/Firebase/Auth/Source/Public/FIRGoogleAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIRGoogleAuthProvider.h
@@ -25,6 +25,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
extern NSString *const FIRGoogleAuthProviderID NS_SWIFT_NAME(GoogleAuthProviderID);
+/**
+ @brief A string constant identifying the Google sign-in method.
+ */
+extern NSString *const _Nonnull FIRGoogleAuthSignInMethod NS_SWIFT_NAME(GoogleAuthSignInMethod);
+
/** @class FIRGoogleAuthProvider
@brief Utility class for constructing Google Sign In credentials.
*/
diff --git a/Firebase/Auth/Source/Public/FIRPhoneAuthProvider.h b/Firebase/Auth/Source/Public/FIRPhoneAuthProvider.h
index 34db683..bd68e84 100644
--- a/Firebase/Auth/Source/Public/FIRPhoneAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIRPhoneAuthProvider.h
@@ -27,6 +27,12 @@ NS_ASSUME_NONNULL_BEGIN
*/
extern NSString *const FIRPhoneAuthProviderID NS_SWIFT_NAME(PhoneAuthProviderID);
+/** @var FIRPhoneAuthProviderID
+ @brief A string constant identifying the phone sign-in method.
+ */
+extern NSString *const _Nonnull FIRPhoneAuthSignInMethod NS_SWIFT_NAME(PhoneAuthSignInMethod);
+
+
/** @typedef FIRVerificationResultCallback
@brief The type of block invoked when a request to send a verification code has finished.
diff --git a/Firebase/Auth/Source/Public/FIRTwitterAuthProvider.h b/Firebase/Auth/Source/Public/FIRTwitterAuthProvider.h
index 2ef32f7..a0d1166 100644
--- a/Firebase/Auth/Source/Public/FIRTwitterAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIRTwitterAuthProvider.h
@@ -25,6 +25,12 @@ NS_ASSUME_NONNULL_BEGIN
*/
extern NSString *const FIRTwitterAuthProviderID NS_SWIFT_NAME(TwitterAuthProviderID);
+/**
+ @brief A string constant identifying the Twitter sign-in method.
+ */
+extern NSString *const _Nonnull FIRTwitterAuthSignInMethod NS_SWIFT_NAME(TwitterAuthSignInMethod);
+
+
/** @class FIRTwitterAuthProvider
@brief Utility class for constructing Twitter credentials.
*/
diff --git a/Firebase/Core/FIROptions.m b/Firebase/Core/FIROptions.m
index 384ef21..b53fa52 100644
--- a/Firebase/Core/FIROptions.m
+++ b/Firebase/Core/FIROptions.m
@@ -43,7 +43,7 @@ NSString *const kFIRIsSignInEnabled = @"IS_SIGNIN_ENABLED";
NSString *const kFIRLibraryVersionID =
@"4" // Major version (one or more digits)
@"00" // Minor version (exactly 2 digits)
- @"17" // Build number (exactly 2 digits)
+ @"18" // Build number (exactly 2 digits)
@"000"; // Fixed "000"
// Plist file name.
NSString *const kServiceInfoFileName = @"GoogleService-Info";
diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec
index 1f18d97..549c720 100644
--- a/FirebaseAuth.podspec
+++ b/FirebaseAuth.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseAuth'
- s.version = '4.4.4'
+ s.version = '4.5.0'
s.summary = 'The official iOS client for Firebase Authentication'
s.description = <<-DESC
diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec
index eec8605..583dc39 100644
--- a/FirebaseCore.podspec
+++ b/FirebaseCore.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseCore'
- s.version = '4.0.17'
+ s.version = '4.0.18'
s.summary = 'Firebase Core for iOS'
s.description = <<-DESC
diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec
index 896dcfb..9af8ec9 100644
--- a/FirebaseFirestore.podspec
+++ b/FirebaseFirestore.podspec
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'FirebaseFirestore'
- s.version = '0.10.3'
+ s.version = '0.10.4'
s.summary = 'Google Cloud Firestore for iOS'
s.description = <<-DESC
diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec
new file mode 100644
index 0000000..caf3023
--- /dev/null
+++ b/FirebaseFunctions.podspec
@@ -0,0 +1,33 @@
+#
+# Be sure to run `pod lib lint FirebaseFunctions.podspec' to ensure this is a
+# valid spec before submitting.
+#
+# Any lines starting with a # are optional, but their use is encouraged
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
+#
+
+Pod::Spec.new do |s|
+ s.name = 'FirebaseFunctions'
+ s.version = '1.0.0'
+ s.summary = 'Cloud Functions for Firebase iOS SDK.'
+
+ s.description = <<-DESC
+iOS SDK for Cloud Functions for Firebase.
+ DESC
+
+ s.homepage = 'https://developers.google.com/'
+ s.authors = 'Google, Inc.'
+ s.source = { :git => 'https://github.com/TBD/FirebaseFunctions.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '8.0'
+
+ s.cocoapods_version = '>= 1.4.0'
+ s.static_framework = true
+ s.prefix_header_file = false
+
+ s.source_files = 'Functions/FirebaseFunctions/**/*'
+ s.public_header_files = 'Functions/FirebaseFunctions/Public/*.h'
+
+ s.dependency 'FirebaseCore', '~> 4.0'
+ s.dependency 'GTMSessionFetcher/Core', '~> 1.1'
+end
diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile
index 71afc2b..f7527d2 100644
--- a/Firestore/Example/Podfile
+++ b/Firestore/Example/Podfile
@@ -1,7 +1,7 @@
# The next line is the forcing function for the Firebase pod. The Firebase
# version's subspecs should depend on the component versions in their
# corresponding podspec's.
-pod 'Firebase/Core', '4.10.1'
+pod 'Firebase/Core', '4.11.0'
use_frameworks!
platform :ios, '8.0'
diff --git a/Firestore/Source/Util/FSTDispatchQueue.mm b/Firestore/Source/Util/FSTDispatchQueue.mm
index 15d6e7b..52482df 100644
--- a/Firestore/Source/Util/FSTDispatchQueue.mm
+++ b/Firestore/Source/Util/FSTDispatchQueue.mm
@@ -230,8 +230,11 @@ NS_ASSUME_NONNULL_BEGIN
block:(void (^)(void))block {
// While not necessarily harmful, we currently don't expect to have multiple callbacks with the
// same timerID in the queue, so defensively reject them.
- FSTAssert(![self containsDelayedCallbackWithTimerID:timerID],
- @"Attempted to schedule multiple callbacks with id %ld", (unsigned long)timerID);
+ // TODO(b/74749605): If a user change happens while offline we can end up with multiple backoff
+ // callbacks in the dispatch queue. This is non-harmful so I'm just disabling the assert until we
+ // get that cleaned up.
+ // FSTAssert(![self containsDelayedCallbackWithTimerID:timerID],
+ // @"Attempted to schedule multiple callbacks with id %ld", (unsigned long)timerID);
FSTDelayedCallback *delayedCallback = [FSTDelayedCallback createAndScheduleWithQueue:self
timerID:timerID
delay:delay
diff --git a/Functions/.clang-format b/Functions/.clang-format
new file mode 100644
index 0000000..fb06210
--- /dev/null
+++ b/Functions/.clang-format
@@ -0,0 +1,7 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+BinPackParameters: false
+AllowAllParametersOfDeclarationOnNextLine: true
+ObjCSpaceBeforeProtocolList: false
+SpacesInContainerLiterals: true
+PointerAlignment: Right
diff --git a/Functions/Backend/index.js b/Functions/Backend/index.js
new file mode 100644
index 0000000..0245f1b
--- /dev/null
+++ b/Functions/Backend/index.js
@@ -0,0 +1,95 @@
+const assert = require('assert');
+const functions = require('firebase-functions');
+
+exports.dataTest = functions.https.onRequest((request, response) => {
+ assert.deepEqual(request.body, {
+ data: {
+ bool: true,
+ int: 2,
+ long: {
+ value: '3',
+ '@type': 'type.googleapis.com/google.protobuf.Int64Value',
+ },
+ string: 'four',
+ array: [5, 6],
+ 'null': null,
+ }
+ });
+ response.send({
+ data: {
+ message: 'stub response',
+ code: 42,
+ long: {
+ value: '420',
+ '@type': 'type.googleapis.com/google.protobuf.Int64Value',
+ },
+ }
+ });
+});
+
+exports.scalarTest = functions.https.onRequest((request, response) => {
+ assert.deepEqual(request.body, { data: 17 });
+ response.send({ data: 76 });
+});
+
+exports.tokenTest = functions.https.onRequest((request, response) => {
+ assert.equal('Bearer token', request.get('Authorization'));
+ assert.deepEqual(request.body, { data: {} });
+ response.send({ data: {} });
+});
+
+exports.instanceIdTest = functions.https.onRequest((request, response) => {
+ assert.equal(request.get('Firebase-Instance-ID-Token'), 'iid');
+ assert.deepEqual(request.body, { data: {} });
+ response.send({ data: {} });
+});
+
+exports.nullTest = functions.https.onRequest((request, response) => {
+ assert.deepEqual(request.body, { data: null });
+ response.send({ data: null });
+});
+
+exports.missingResultTest = functions.https.onRequest((request, response) => {
+ assert.deepEqual(request.body, { data: null });
+ response.send({});
+});
+
+exports.unhandledErrorTest = functions.https.onRequest((request, response) => {
+ // Fail in a way that the client shouldn't see.
+ throw 'nope';
+});
+
+exports.unknownErrorTest = functions.https.onRequest((request, response) => {
+ // Send an http error with a body with an explicit code.
+ response.status(400).send({
+ error: {
+ status: 'THIS_IS_NOT_VALID',
+ message: 'this should be ignored',
+ },
+ });
+});
+
+exports.explicitErrorTest = functions.https.onRequest((request, response) => {
+ // Send an http error with a body with an explicit code.
+ // Note that eventually the SDK will have a helper to automatically return
+ // the appropriate http status code for an error.
+ response.status(400).send({
+ error: {
+ status: 'OUT_OF_RANGE',
+ message: 'explicit nope',
+ details: {
+ start: 10,
+ end: 20,
+ long: {
+ value: '30',
+ '@type': 'type.googleapis.com/google.protobuf.Int64Value',
+ },
+ },
+ },
+ });
+});
+
+exports.httpErrorTest = functions.https.onRequest((request, response) => {
+ // Send an http error with no body.
+ response.status(400).send();
+});
diff --git a/Functions/Backend/package.json b/Functions/Backend/package.json
new file mode 100644
index 0000000..c227bb1
--- /dev/null
+++ b/Functions/Backend/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "functions",
+ "description": "Cloud Functions for Firebase",
+ "dependencies": {
+ "firebase-admin": "~4.2.1",
+ "firebase-functions": "^0.5.7"
+ },
+ "private": true,
+ "devDependencies": {
+ "@google-cloud/functions-emulator": "^1.0.0-alpha.21"
+ }
+}
diff --git a/Functions/Backend/start.sh b/Functions/Backend/start.sh
new file mode 100755
index 0000000..b09675a
--- /dev/null
+++ b/Functions/Backend/start.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 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.
+
+# Sets up a project with the functions CLI and starts a backend to run
+# integration tests against.
+
+set -e
+
+# Get the absolute path to the directory containing this script.
+SCRIPT_DIR="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)"
+TEMP_DIR="$(mktemp -d -t firebase-functions)"
+echo "Creating functions in ${TEMP_DIR}"
+
+# Set up the functions directory.
+cp "${SCRIPT_DIR}/index.js" "${TEMP_DIR}/"
+cp "${SCRIPT_DIR}/package.json" "${TEMP_DIR}/"
+cd "${TEMP_DIR}"
+npm install
+
+# Start the server.
+FUNCTIONS_BIN="./node_modules/.bin/functions"
+"${FUNCTIONS_BIN}" config set projectId functions-integration-test
+"${FUNCTIONS_BIN}" config set supervisorPort 5005
+"${FUNCTIONS_BIN}" config set region us-central1
+"${FUNCTIONS_BIN}" config set verbose true
+"${FUNCTIONS_BIN}" restart
+"${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 nullTest --trigger-http
+"${FUNCTIONS_BIN}" deploy missingResultTest --trigger-http
+"${FUNCTIONS_BIN}" deploy unhandledErrorTest --trigger-http
+"${FUNCTIONS_BIN}" deploy unknownErrorTest --trigger-http
+"${FUNCTIONS_BIN}" deploy explicitErrorTest --trigger-http
+"${FUNCTIONS_BIN}" deploy httpErrorTest --trigger-http
+
+# Wait for the user to tell us to stop the server.
+echo "Functions emulator now running in ${TEMP_DIR}."
+read -n 1 -p "*** Press any key to stop the server. ***"
+echo "\nStopping the emulator..."
+"${FUNCTIONS_BIN}" stop
diff --git a/Functions/CHANGELOG.md b/Functions/CHANGELOG.md
new file mode 100644
index 0000000..d2ea864
--- /dev/null
+++ b/Functions/CHANGELOG.md
@@ -0,0 +1,2 @@
+# v1.0.0
+- Initial public release \ No newline at end of file
diff --git a/Functions/Example/FirebaseFunctions.xcodeproj/project.pbxproj b/Functions/Example/FirebaseFunctions.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..d70f4b5
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions.xcodeproj/project.pbxproj
@@ -0,0 +1,848 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
+ 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
+ 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
+ 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; };
+ 6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; };
+ 6003F59E195388D20070C39A /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* FIRAppDelegate.m */; };
+ 6003F5A7195388D20070C39A /* FIRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* FIRViewController.m */; };
+ 6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; };
+ 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
+ 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
+ 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
+ 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
+ 6003F5BC195388D20070C39A /* FIRFunctionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* FIRFunctionsTests.m */; };
+ 633D50991C0FDF68085030B5 /* Pods_FirebaseFunctions_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B954281766FFD7C7C9970E9B /* Pods_FirebaseFunctions_Example.framework */; };
+ 6358342A9F1AF395C6C52471 /* Pods_FirebaseFunctions_IntegrationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A4C1781DC97515D32B33DBD /* Pods_FirebaseFunctions_IntegrationTests.framework */; };
+ 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
+ 78F883E44C88CC18414F3DAF /* Pods_FirebaseFunctions_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A19679D6C21E3206B4A13697 /* Pods_FirebaseFunctions_Tests.framework */; };
+ 7C58B03A1F1441F0005ED954 /* FUNSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C58B0391F1441F0005ED954 /* FUNSerializerTests.m */; };
+ 7CBFAA82205702AB00A65866 /* FIRIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C9BFD3F1F10A12F001A19ED /* FIRIntegrationTests.m */; };
+ 7CBFAA86205702AB00A65866 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
+ 7CBFAA87205702AB00A65866 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
+ 7CBFAA88205702AB00A65866 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
+ 7CBFAA89205702AB00A65866 /* Pods_FirebaseFunctions_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A19679D6C21E3206B4A13697 /* Pods_FirebaseFunctions_Tests.framework */; };
+ 7CBFAA8B205702AB00A65866 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
+ 7CF3BEC21F97EE2F00B16B6E /* FUNFakeInstanceID.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF3BEC01F97EE2F00B16B6E /* FUNFakeInstanceID.m */; };
+ 7CF563091F1FE70600FEE1F4 /* FUNFakeApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF563081F1FE70600FEE1F4 /* FUNFakeApp.m */; };
+ 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 6003F589195388D20070C39A;
+ remoteInfo = FirebaseFunctions;
+ };
+ 7CBFAA7F205702AB00A65866 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 6003F589195388D20070C39A;
+ remoteInfo = FirebaseFunctions;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 0A4C1781DC97515D32B33DBD /* Pods_FirebaseFunctions_IntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FirebaseFunctions_IntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 501CFEC7487BD4C12FCEAB03 /* Pods-FirebaseFunctions_IntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseFunctions_IntegrationTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseFunctions_IntegrationTests/Pods-FirebaseFunctions_IntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
+ 59519EC771AF4770F85B6534 /* Pods-FirebaseFunctions_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseFunctions_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseFunctions_Example/Pods-FirebaseFunctions_Example.debug.xcconfig"; sourceTree = "<group>"; };
+ 5B43C813C653DE3455952E9B /* Pods-FirebaseFunctions_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseFunctions_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseFunctions_Tests/Pods-FirebaseFunctions_Tests.release.xcconfig"; sourceTree = "<group>"; };
+ 6003F58A195388D20070C39A /* FirebaseFunctions_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FirebaseFunctions_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 6003F595195388D20070C39A /* FirebaseFunctions-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FirebaseFunctions-Info.plist"; sourceTree = "<group>"; };
+ 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 6003F59C195388D20070C39A /* FIRAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FIRAppDelegate.h; sourceTree = "<group>"; };
+ 6003F59D195388D20070C39A /* FIRAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRAppDelegate.m; sourceTree = "<group>"; };
+ 6003F5A5195388D20070C39A /* FIRViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FIRViewController.h; sourceTree = "<group>"; };
+ 6003F5A6195388D20070C39A /* FIRViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRViewController.m; sourceTree = "<group>"; };
+ 6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 6003F5AE195388D20070C39A /* FirebaseFunctions_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FirebaseFunctions_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
+ 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
+ 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 6003F5BB195388D20070C39A /* FIRFunctionsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRFunctionsTests.m; sourceTree = "<group>"; };
+ 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+ 7BEA793625C8DE7C8EC60006 /* FirebaseFunctions.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = FirebaseFunctions.podspec; path = ../FirebaseFunctions.podspec; sourceTree = "<group>"; };
+ 7C58B0391F1441F0005ED954 /* FUNSerializerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUNSerializerTests.m; sourceTree = "<group>"; };
+ 7C9BFD3F1F10A12F001A19ED /* FIRIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRIntegrationTests.m; sourceTree = "<group>"; };
+ 7CBFAA91205702AB00A65866 /* FirebaseFunctions_IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FirebaseFunctions_IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7CBFAA92205702AC00A65866 /* FirebaseFunctions_Tests copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "FirebaseFunctions_Tests copy-Info.plist"; path = "/Users/klimt/src/firebase-ios-sdk/Functions/Example/FirebaseFunctions_Tests copy-Info.plist"; sourceTree = "<absolute>"; };
+ 7CF3BEC01F97EE2F00B16B6E /* FUNFakeInstanceID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUNFakeInstanceID.m; sourceTree = "<group>"; };
+ 7CF3BEC11F97EE2F00B16B6E /* FUNFakeInstanceID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUNFakeInstanceID.h; sourceTree = "<group>"; };
+ 7CF563081F1FE70600FEE1F4 /* FUNFakeApp.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUNFakeApp.m; sourceTree = "<group>"; };
+ 7CF5630A1F1FE76700FEE1F4 /* FUNFakeApp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUNFakeApp.h; sourceTree = "<group>"; };
+ 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ A19679D6C21E3206B4A13697 /* Pods_FirebaseFunctions_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FirebaseFunctions_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ B954281766FFD7C7C9970E9B /* Pods_FirebaseFunctions_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FirebaseFunctions_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ E0A8D570636E99E7C3396DF8 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
+ E2E6249788F1618471335BE7 /* Pods-FirebaseFunctions_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseFunctions_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseFunctions_Example/Pods-FirebaseFunctions_Example.release.xcconfig"; sourceTree = "<group>"; };
+ F1F2A7C03C10A3A03F9502B8 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
+ F840F9EDCB950E7509527AB7 /* Pods-FirebaseFunctions_IntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseFunctions_IntegrationTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseFunctions_IntegrationTests/Pods-FirebaseFunctions_IntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
+ FFE894EDD87F1EF24F0ED8DD /* Pods-FirebaseFunctions_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseFunctions_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseFunctions_Tests/Pods-FirebaseFunctions_Tests.debug.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 6003F587195388D20070C39A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
+ 6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
+ 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
+ 633D50991C0FDF68085030B5 /* Pods_FirebaseFunctions_Example.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6003F5AB195388D20070C39A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */,
+ 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */,
+ 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */,
+ 78F883E44C88CC18414F3DAF /* Pods_FirebaseFunctions_Tests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7CBFAA85205702AB00A65866 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7CBFAA86205702AB00A65866 /* XCTest.framework in Frameworks */,
+ 7CBFAA87205702AB00A65866 /* UIKit.framework in Frameworks */,
+ 7CBFAA88205702AB00A65866 /* Foundation.framework in Frameworks */,
+ 7CBFAA89205702AB00A65866 /* Pods_FirebaseFunctions_Tests.framework in Frameworks */,
+ 6358342A9F1AF395C6C52471 /* Pods_FirebaseFunctions_IntegrationTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 004DC60D1A62294B06E83453 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 59519EC771AF4770F85B6534 /* Pods-FirebaseFunctions_Example.debug.xcconfig */,
+ E2E6249788F1618471335BE7 /* Pods-FirebaseFunctions_Example.release.xcconfig */,
+ FFE894EDD87F1EF24F0ED8DD /* Pods-FirebaseFunctions_Tests.debug.xcconfig */,
+ 5B43C813C653DE3455952E9B /* Pods-FirebaseFunctions_Tests.release.xcconfig */,
+ 501CFEC7487BD4C12FCEAB03 /* Pods-FirebaseFunctions_IntegrationTests.debug.xcconfig */,
+ F840F9EDCB950E7509527AB7 /* Pods-FirebaseFunctions_IntegrationTests.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ 6003F581195388D10070C39A = {
+ isa = PBXGroup;
+ children = (
+ 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */,
+ 6003F593195388D20070C39A /* Example for FirebaseFunctions */,
+ 7C70065B20572C1B007A5573 /* TestUtils */,
+ 7CFC6F8720570365005630C2 /* IntegrationTests */,
+ 6003F5B5195388D20070C39A /* Tests */,
+ 6003F58C195388D20070C39A /* Frameworks */,
+ 6003F58B195388D20070C39A /* Products */,
+ 004DC60D1A62294B06E83453 /* Pods */,
+ 7CBFAA92205702AC00A65866 /* FirebaseFunctions_Tests copy-Info.plist */,
+ );
+ sourceTree = "<group>";
+ };
+ 6003F58B195388D20070C39A /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F58A195388D20070C39A /* FirebaseFunctions_Example.app */,
+ 6003F5AE195388D20070C39A /* FirebaseFunctions_Tests.xctest */,
+ 7CBFAA91205702AB00A65866 /* FirebaseFunctions_IntegrationTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 6003F58C195388D20070C39A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F58D195388D20070C39A /* Foundation.framework */,
+ 6003F58F195388D20070C39A /* CoreGraphics.framework */,
+ 6003F591195388D20070C39A /* UIKit.framework */,
+ 6003F5AF195388D20070C39A /* XCTest.framework */,
+ B954281766FFD7C7C9970E9B /* Pods_FirebaseFunctions_Example.framework */,
+ A19679D6C21E3206B4A13697 /* Pods_FirebaseFunctions_Tests.framework */,
+ 0A4C1781DC97515D32B33DBD /* Pods_FirebaseFunctions_IntegrationTests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 6003F593195388D20070C39A /* Example for FirebaseFunctions */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F59C195388D20070C39A /* FIRAppDelegate.h */,
+ 6003F59D195388D20070C39A /* FIRAppDelegate.m */,
+ 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */,
+ 6003F5A5195388D20070C39A /* FIRViewController.h */,
+ 6003F5A6195388D20070C39A /* FIRViewController.m */,
+ 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */,
+ 6003F5A8195388D20070C39A /* Images.xcassets */,
+ 6003F594195388D20070C39A /* Supporting Files */,
+ );
+ name = "Example for FirebaseFunctions";
+ path = FirebaseFunctions;
+ sourceTree = "<group>";
+ };
+ 6003F594195388D20070C39A /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F595195388D20070C39A /* FirebaseFunctions-Info.plist */,
+ 6003F596195388D20070C39A /* InfoPlist.strings */,
+ 6003F599195388D20070C39A /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 6003F5B5195388D20070C39A /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F5BB195388D20070C39A /* FIRFunctionsTests.m */,
+ 7C58B0391F1441F0005ED954 /* FUNSerializerTests.m */,
+ 6003F5B6195388D20070C39A /* Supporting Files */,
+ );
+ path = Tests;
+ sourceTree = "<group>";
+ };
+ 6003F5B6195388D20070C39A /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F5B7195388D20070C39A /* Tests-Info.plist */,
+ 6003F5B8195388D20070C39A /* InfoPlist.strings */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = {
+ isa = PBXGroup;
+ children = (
+ 7BEA793625C8DE7C8EC60006 /* FirebaseFunctions.podspec */,
+ E0A8D570636E99E7C3396DF8 /* README.md */,
+ F1F2A7C03C10A3A03F9502B8 /* LICENSE */,
+ );
+ name = "Podspec Metadata";
+ sourceTree = "<group>";
+ };
+ 7C70065B20572C1B007A5573 /* TestUtils */ = {
+ isa = PBXGroup;
+ children = (
+ 7CF5630A1F1FE76700FEE1F4 /* FUNFakeApp.h */,
+ 7CF563081F1FE70600FEE1F4 /* FUNFakeApp.m */,
+ 7CF3BEC11F97EE2F00B16B6E /* FUNFakeInstanceID.h */,
+ 7CF3BEC01F97EE2F00B16B6E /* FUNFakeInstanceID.m */,
+ );
+ path = TestUtils;
+ sourceTree = "<group>";
+ };
+ 7CFC6F8720570365005630C2 /* IntegrationTests */ = {
+ isa = PBXGroup;
+ children = (
+ 7C9BFD3F1F10A12F001A19ED /* FIRIntegrationTests.m */,
+ );
+ path = IntegrationTests;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 6003F589195388D20070C39A /* FirebaseFunctions_Example */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "FirebaseFunctions_Example" */;
+ buildPhases = (
+ C1B1E870DA1D732EC2F1F946 /* [CP] Check Pods Manifest.lock */,
+ 6003F586195388D20070C39A /* Sources */,
+ 6003F587195388D20070C39A /* Frameworks */,
+ 6003F588195388D20070C39A /* Resources */,
+ BB7A7FC40453827CC7541BB7 /* [CP] Embed Pods Frameworks */,
+ 0409BC62B2C369D14416E480 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = FirebaseFunctions_Example;
+ productName = FirebaseFunctions;
+ productReference = 6003F58A195388D20070C39A /* FirebaseFunctions_Example.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 6003F5AD195388D20070C39A /* FirebaseFunctions_Tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "FirebaseFunctions_Tests" */;
+ buildPhases = (
+ D9E332DA9E27ECA02C2B45D2 /* [CP] Check Pods Manifest.lock */,
+ 6003F5AA195388D20070C39A /* Sources */,
+ 6003F5AB195388D20070C39A /* Frameworks */,
+ 6003F5AC195388D20070C39A /* Resources */,
+ 3B7914C40161367B84BC9E52 /* [CP] Embed Pods Frameworks */,
+ F0A35EE9B43049BA133AD88F /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 6003F5B4195388D20070C39A /* PBXTargetDependency */,
+ );
+ name = FirebaseFunctions_Tests;
+ productName = FirebaseFunctionsTests;
+ productReference = 6003F5AE195388D20070C39A /* FirebaseFunctions_Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 7CBFAA7D205702AB00A65866 /* FirebaseFunctions_IntegrationTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7CBFAA8E205702AB00A65866 /* Build configuration list for PBXNativeTarget "FirebaseFunctions_IntegrationTests" */;
+ buildPhases = (
+ 7CBFAA80205702AB00A65866 /* [CP] Check Pods Manifest.lock */,
+ 7CBFAA81205702AB00A65866 /* Sources */,
+ 7CBFAA85205702AB00A65866 /* Frameworks */,
+ 7CBFAA8A205702AB00A65866 /* Resources */,
+ 7CBFAA8C205702AB00A65866 /* [CP] Embed Pods Frameworks */,
+ 7CBFAA8D205702AB00A65866 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 7CBFAA7E205702AB00A65866 /* PBXTargetDependency */,
+ );
+ name = FirebaseFunctions_IntegrationTests;
+ productName = FirebaseFunctionsTests;
+ productReference = 7CBFAA91205702AB00A65866 /* FirebaseFunctions_IntegrationTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 6003F582195388D10070C39A /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ CLASSPREFIX = FIR;
+ LastUpgradeCheck = 0720;
+ ORGANIZATIONNAME = "Google, Inc.";
+ TargetAttributes = {
+ 6003F5AD195388D20070C39A = {
+ TestTargetID = 6003F589195388D20070C39A;
+ };
+ };
+ };
+ buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "FirebaseFunctions" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 6003F581195388D10070C39A;
+ productRefGroup = 6003F58B195388D20070C39A /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 6003F589195388D20070C39A /* FirebaseFunctions_Example */,
+ 6003F5AD195388D20070C39A /* FirebaseFunctions_Tests */,
+ 7CBFAA7D205702AB00A65866 /* FirebaseFunctions_IntegrationTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 6003F588195388D20070C39A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */,
+ 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */,
+ 6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
+ 6003F598195388D20070C39A /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6003F5AC195388D20070C39A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7CBFAA8A205702AB00A65866 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7CBFAA8B205702AB00A65866 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 0409BC62B2C369D14416E480 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_Example/Pods-FirebaseFunctions_Example-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 3B7914C40161367B84BC9E52 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_Tests/Pods-FirebaseFunctions_Tests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 7CBFAA80205702AB00A65866 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-FirebaseFunctions_IntegrationTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 7CBFAA8C205702AB00A65866 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_IntegrationTests/Pods-FirebaseFunctions_IntegrationTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 7CBFAA8D205702AB00A65866 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_IntegrationTests/Pods-FirebaseFunctions_IntegrationTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BB7A7FC40453827CC7541BB7 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_Example/Pods-FirebaseFunctions_Example-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_Example/Pods-FirebaseFunctions_Example-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ C1B1E870DA1D732EC2F1F946 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-FirebaseFunctions_Example-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ D9E332DA9E27ECA02C2B45D2 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-FirebaseFunctions_Tests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ F0A35EE9B43049BA133AD88F /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseFunctions_Tests/Pods-FirebaseFunctions_Tests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 6003F586195388D20070C39A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7CF563091F1FE70600FEE1F4 /* FUNFakeApp.m in Sources */,
+ 6003F59E195388D20070C39A /* FIRAppDelegate.m in Sources */,
+ 6003F5A7195388D20070C39A /* FIRViewController.m in Sources */,
+ 7CF3BEC21F97EE2F00B16B6E /* FUNFakeInstanceID.m in Sources */,
+ 6003F59A195388D20070C39A /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6003F5AA195388D20070C39A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7C58B03A1F1441F0005ED954 /* FUNSerializerTests.m in Sources */,
+ 6003F5BC195388D20070C39A /* FIRFunctionsTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7CBFAA81205702AB00A65866 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7CBFAA82205702AB00A65866 /* FIRIntegrationTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 6003F5B4195388D20070C39A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 6003F589195388D20070C39A /* FirebaseFunctions_Example */;
+ targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */;
+ };
+ 7CBFAA7E205702AB00A65866 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 6003F589195388D20070C39A /* FirebaseFunctions_Example */;
+ targetProxy = 7CBFAA7F205702AB00A65866 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 6003F596195388D20070C39A /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 6003F597195388D20070C39A /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ 6003F5B8195388D20070C39A /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 6003F5B9195388D20070C39A /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 71719F9E1E33DC2100824A3D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 6003F5BD195388D20070C39A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 6003F5BE195388D20070C39A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 6003F5C0195388D20070C39A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 59519EC771AF4770F85B6534 /* Pods-FirebaseFunctions_Example.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ INFOPLIST_FILE = "FirebaseFunctions/FirebaseFunctions-Info.plist";
+ MODULE_NAME = ExampleApp;
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ 6003F5C1195388D20070C39A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E2E6249788F1618471335BE7 /* Pods-FirebaseFunctions_Example.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ INFOPLIST_FILE = "FirebaseFunctions/FirebaseFunctions-Info.plist";
+ MODULE_NAME = ExampleApp;
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+ 6003F5C3195388D20070C39A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FFE894EDD87F1EF24F0ED8DD /* Pods-FirebaseFunctions_Tests.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ );
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../FirebaseFunctions";
+ INFOPLIST_FILE = "Tests/Tests-Info.plist";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FirebaseFunctions_Example.app/FirebaseFunctions_Example";
+ WRAPPER_EXTENSION = xctest;
+ };
+ name = Debug;
+ };
+ 6003F5C4195388D20070C39A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5B43C813C653DE3455952E9B /* Pods-FirebaseFunctions_Tests.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ );
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../FirebaseFunctions";
+ INFOPLIST_FILE = "Tests/Tests-Info.plist";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FirebaseFunctions_Example.app/FirebaseFunctions_Example";
+ WRAPPER_EXTENSION = xctest;
+ };
+ name = Release;
+ };
+ 7CBFAA8F205702AB00A65866 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 501CFEC7487BD4C12FCEAB03 /* Pods-FirebaseFunctions_IntegrationTests.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ );
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../FirebaseFunctions";
+ INFOPLIST_FILE = "IntegrationTests/IntegrationTests-Info.plist";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FirebaseFunctions_Example.app/FirebaseFunctions_Example";
+ WRAPPER_EXTENSION = xctest;
+ };
+ name = Debug;
+ };
+ 7CBFAA90205702AB00A65866 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = F840F9EDCB950E7509527AB7 /* Pods-FirebaseFunctions_IntegrationTests.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ );
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../FirebaseFunctions";
+ INFOPLIST_FILE = "IntegrationTests/IntegrationTests-Info.plist";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FirebaseFunctions_Example.app/FirebaseFunctions_Example";
+ WRAPPER_EXTENSION = xctest;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 6003F585195388D10070C39A /* Build configuration list for PBXProject "FirebaseFunctions" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6003F5BD195388D20070C39A /* Debug */,
+ 6003F5BE195388D20070C39A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "FirebaseFunctions_Example" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6003F5C0195388D20070C39A /* Debug */,
+ 6003F5C1195388D20070C39A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "FirebaseFunctions_Tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6003F5C3195388D20070C39A /* Debug */,
+ 6003F5C4195388D20070C39A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7CBFAA8E205702AB00A65866 /* Build configuration list for PBXNativeTarget "FirebaseFunctions_IntegrationTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7CBFAA8F205702AB00A65866 /* Debug */,
+ 7CBFAA90205702AB00A65866 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 6003F582195388D10070C39A /* Project object */;
+}
diff --git a/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions-Example.xcscheme b/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions-Example.xcscheme
new file mode 100644
index 0000000..b9983e8
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions-Example.xcscheme
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0720"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6003F589195388D20070C39A"
+ BuildableName = "FirebaseFunctions_Example.app"
+ BlueprintName = "FirebaseFunctions_Example"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6003F5AD195388D20070C39A"
+ BuildableName = "FirebaseFunctions_Tests.xctest"
+ BlueprintName = "FirebaseFunctions_Tests"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "7CBFAA7D205702AB00A65866"
+ BuildableName = "FirebaseFunctions_IntegrationTests.xctest"
+ BlueprintName = "FirebaseFunctions_IntegrationTests"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6003F589195388D20070C39A"
+ BuildableName = "FirebaseFunctions_Example.app"
+ BlueprintName = "FirebaseFunctions_Example"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6003F589195388D20070C39A"
+ BuildableName = "FirebaseFunctions_Example.app"
+ BlueprintName = "FirebaseFunctions_Example"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6003F589195388D20070C39A"
+ BuildableName = "FirebaseFunctions_Example.app"
+ BlueprintName = "FirebaseFunctions_Example"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_IntegrationTests.xcscheme b/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_IntegrationTests.xcscheme
new file mode 100644
index 0000000..46914fb
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_IntegrationTests.xcscheme
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0930"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "7CBFAA7D205702AB00A65866"
+ BuildableName = "FirebaseFunctions_IntegrationTests.xctest"
+ BlueprintName = "FirebaseFunctions_IntegrationTests"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_Tests.xcscheme b/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_Tests.xcscheme
new file mode 100644
index 0000000..26063f9
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions.xcodeproj/xcshareddata/xcschemes/FirebaseFunctions_Tests.xcscheme
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0930"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6003F5AD195388D20070C39A"
+ BuildableName = "FirebaseFunctions_Tests.xctest"
+ BlueprintName = "FirebaseFunctions_Tests"
+ ReferencedContainer = "container:FirebaseFunctions.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Functions/Example/FirebaseFunctions/Base.lproj/LaunchScreen.storyboard b/Functions/Example/FirebaseFunctions/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..66a7681
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="EHf-IW-A2E">
+ <objects>
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
+ <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="53" y="375"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/Functions/Example/FirebaseFunctions/Base.lproj/Main.storyboard b/Functions/Example/FirebaseFunctions/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..d164a23
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/Base.lproj/Main.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="whP-gf-Uak">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="wQg-tq-qST">
+ <objects>
+ <viewController id="whP-gf-Uak" customClass="FIRViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="uEw-UM-LJ8"/>
+ <viewControllerLayoutGuide type="bottom" id="Mvr-aV-6Um"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="TpU-gO-2f1">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="tc2-Qw-aMS" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="305" y="433"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/Functions/Example/FirebaseFunctions/FIRAppDelegate.h b/Functions/Example/FirebaseFunctions/FIRAppDelegate.h
new file mode 100644
index 0000000..1d6d40b
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/FIRAppDelegate.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 FIRAppDelegate : UIResponder<UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/Functions/Example/FirebaseFunctions/FIRAppDelegate.m b/Functions/Example/FirebaseFunctions/FIRAppDelegate.m
new file mode 100644
index 0000000..9568d06
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/FIRAppDelegate.m
@@ -0,0 +1,55 @@
+// 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"
+
+@implementation FIRAppDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ 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/Functions/Example/FirebaseFunctions/FIRViewController.h b/Functions/Example/FirebaseFunctions/FIRViewController.h
new file mode 100644
index 0000000..5c4dff5
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/FIRViewController.h
@@ -0,0 +1,19 @@
+// 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/Functions/Example/FirebaseFunctions/FIRViewController.m b/Functions/Example/FirebaseFunctions/FIRViewController.m
new file mode 100644
index 0000000..027aabf
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/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/Functions/Example/FirebaseFunctions/FirebaseFunctions-Info.plist b/Functions/Example/FirebaseFunctions/FirebaseFunctions-Info.plist
new file mode 100644
index 0000000..fc26896
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/FirebaseFunctions-Info.plist
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ </dict>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/Functions/Example/FirebaseFunctions/Images.xcassets/AppIcon.appiconset/Contents.json b/Functions/Example/FirebaseFunctions/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d7070bc
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,93 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "20x20",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "20x20",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "20x20",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "20x20",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "83.5x83.5",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Functions/Example/FirebaseFunctions/en.lproj/InfoPlist.strings b/Functions/Example/FirebaseFunctions/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..477b28f
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/Functions/Example/FirebaseFunctions/main.m b/Functions/Example/FirebaseFunctions/main.m
new file mode 100644
index 0000000..39c05a5
--- /dev/null
+++ b/Functions/Example/FirebaseFunctions/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/Functions/Example/IntegrationTests/FIRIntegrationTests.m b/Functions/Example/IntegrationTests/FIRIntegrationTests.m
new file mode 100644
index 0000000..15a5af5
--- /dev/null
+++ b/Functions/Example/IntegrationTests/FIRIntegrationTests.m
@@ -0,0 +1,190 @@
+// 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 XCTest;
+
+#import "FIRError.h"
+#import "FIRFunctions+Internal.h"
+#import "FIRFunctions.h"
+#import "FIRHTTPSCallable.h"
+#import "FUNFakeApp.h"
+#import "FUNFakeInstanceID.h"
+
+@interface FIRIntegrationTests : XCTestCase {
+ FIRFunctions *_functions;
+}
+@end
+
+@implementation FIRIntegrationTests
+
+- (void)setUp {
+ [super setUp];
+ id app = [[FUNFakeApp alloc] initWithProjectID:@"functions-integration-test"];
+ _functions = [FIRFunctions functionsForApp:app];
+ [_functions useLocalhost];
+}
+
+- (void)tearDown {
+ [super tearDown];
+}
+
+- (void)testData {
+ NSDictionary *data = @{
+ @"bool" : @YES,
+ @"int" : @2,
+ @"long" : @3L,
+ @"string" : @"four",
+ @"array" : @[ @5, @6 ],
+ @"null" : [NSNull null],
+ };
+
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"dataTest"];
+ [function callWithObject:data
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertEqualObjects(@"stub response", result.data[@"message"]);
+ XCTAssertEqualObjects(@42, result.data[@"code"]);
+ XCTAssertEqualObjects(@420L, result.data[@"long"]);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testScalar {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"scalarTest"];
+ [function callWithObject:@17
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertEqualObjects(@76, result.data);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testToken {
+ // Recreate _functions with a token.
+ id app = [[FUNFakeApp alloc] initWithProjectID:@"functions-integration-test" token:@"token"];
+ FIRFunctions *functions = [FIRFunctions functionsForApp:app];
+ [functions useLocalhost];
+
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [functions HTTPSCallableWithName:@"tokenTest"];
+ [function callWithObject:@{}
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertEqualObjects(@{}, result.data);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testInstanceID {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"instanceIdTest"];
+ [function callWithObject:@{}
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertEqualObjects(@{}, result.data);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testNull {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"nullTest"];
+ [function callWithObject:[NSNull null]
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertEqualObjects([NSNull null], result.data);
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+
+ // Test the version with no arguments.
+ [function
+ callWithCompletion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertEqualObjects([NSNull null], result.data);
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testMissingResult {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"missingResultTest"];
+ [function
+ callWithCompletion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqual(FIRFunctionsErrorCodeInternal, error.code);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testUnhandledError {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"unhandledErrorTest"];
+ [function callWithObject:@{}
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqual(FIRFunctionsErrorCodeInternal, error.code);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testUnknownError {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"unknownErrorTest"];
+ [function callWithObject:@{}
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqual(FIRFunctionsErrorCodeInternal, error.code);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testExplicitError {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"explicitErrorTest"];
+ [function callWithObject:@{}
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqual(FIRFunctionsErrorCodeOutOfRange, error.code);
+ XCTAssertEqualObjects(@"explicit nope", error.userInfo[NSLocalizedDescriptionKey]);
+ NSDictionary *expectedDetails = @{ @"start" : @10, @"end" : @20, @"long" : @30L };
+ XCTAssertEqualObjects(expectedDetails, error.userInfo[FIRFunctionsErrorDetailsKey]);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+- (void)testHttpError {
+ XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
+ FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"httpErrorTest"];
+ [function callWithObject:@{}
+ completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqual(FIRFunctionsErrorCodeInvalidArgument, error.code);
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:10];
+}
+
+@end
diff --git a/Functions/Example/IntegrationTests/IntegrationTests-Info.plist b/Functions/Example/IntegrationTests/IntegrationTests-Info.plist
new file mode 100644
index 0000000..169b6f7
--- /dev/null
+++ b/Functions/Example/IntegrationTests/IntegrationTests-Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/Functions/Example/Podfile b/Functions/Example/Podfile
new file mode 100644
index 0000000..ea07e11
--- /dev/null
+++ b/Functions/Example/Podfile
@@ -0,0 +1,16 @@
+use_frameworks!
+
+target 'FirebaseFunctions_Example' do
+ platform :ios, '8.0'
+
+ pod 'FirebaseCore', :path => '../../'
+ pod 'FirebaseFunctions', :path => '../../'
+
+ target 'FirebaseFunctions_Tests' do
+ inherit! :search_paths
+ end
+
+ target 'FirebaseFunctions_IntegrationTests' do
+ inherit! :search_paths
+ end
+end
diff --git a/Functions/Example/TestUtils/FUNFakeApp.h b/Functions/Example/TestUtils/FUNFakeApp.h
new file mode 100644
index 0000000..d07262b
--- /dev/null
+++ b/Functions/Example/TestUtils/FUNFakeApp.h
@@ -0,0 +1,39 @@
+/*
+ * 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/Foundation.h>
+
+@class FUNFakeOptions;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * FUNFakeApp is a mock app to use for tests.
+ */
+@interface FUNFakeApp : NSObject
+
+- (id)init NS_UNAVAILABLE;
+
+- (instancetype)initWithProjectID:(NSString *)projectID;
+
+- (instancetype)initWithProjectID:(NSString *)projectID
+ token:(NSString *_Nullable)token NS_DESIGNATED_INITIALIZER;
+
+@property(nonatomic, strong, readonly) FUNFakeOptions *options;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/Example/TestUtils/FUNFakeApp.m b/Functions/Example/TestUtils/FUNFakeApp.m
new file mode 100644
index 0000000..5b31d01
--- /dev/null
+++ b/Functions/Example/TestUtils/FUNFakeApp.m
@@ -0,0 +1,71 @@
+/*
+ * 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 "FUNFakeApp.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FUNFakeOptions : NSObject
+
+@property(nonatomic, readonly, copy) NSString *projectID;
+
+- (id)init NS_UNAVAILABLE;
+
+- (instancetype)initWithProjectID:(NSString *)projectID NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation FUNFakeOptions
+
+- (instancetype)initWithProjectID:(NSString *)projectID {
+ self = [super init];
+ if (self) {
+ self->_projectID = [projectID copy];
+ }
+ return self;
+}
+
+@end
+
+@interface FUNFakeApp () {
+ NSString *_token;
+}
+@end
+
+@implementation FUNFakeApp
+
+- (instancetype)initWithProjectID:(NSString *)projectID {
+ return [self initWithProjectID:projectID token:nil];
+}
+
+- (instancetype)initWithProjectID:(NSString *)projectID token:(NSString *_Nullable)token {
+ self = [super init];
+ if (self) {
+ _options = [[FUNFakeOptions alloc] initWithProjectID:projectID];
+ _token = [token copy];
+ }
+ return self;
+}
+
+- (void)getTokenForcingRefresh:(BOOL)forceRefresh
+ withCallback:
+ (void (^)(NSString *_Nullable token, NSError *_Nullable error))callback {
+ callback(_token, nil);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/Example/TestUtils/FUNFakeInstanceID.h b/Functions/Example/TestUtils/FUNFakeInstanceID.h
new file mode 100644
index 0000000..9925410
--- /dev/null
+++ b/Functions/Example/TestUtils/FUNFakeInstanceID.h
@@ -0,0 +1,34 @@
+/*
+ * 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/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * This FIRInstanceID is a mock instance ID provider to use for tests.
+ * Since FirebaseFunctions loads FIRInstanceID as a weak dependency by reflection, we just have to
+ * make a class with the same name.
+ */
+@interface FIRInstanceID : NSObject
+
++ (instancetype)instanceID;
+
+- (NSString *)token;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/Example/TestUtils/FUNFakeInstanceID.m b/Functions/Example/TestUtils/FUNFakeInstanceID.m
new file mode 100644
index 0000000..a81e67a
--- /dev/null
+++ b/Functions/Example/TestUtils/FUNFakeInstanceID.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 "FUNFakeInstanceID.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRInstanceID
+
++ (instancetype)instanceID {
+ return [[FIRInstanceID alloc] init];
+}
+
+- (NSString *)token {
+ return @"iid";
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/Example/Tests/FIRFunctionsTests.m b/Functions/Example/Tests/FIRFunctionsTests.m
new file mode 100644
index 0000000..bec96e6
--- /dev/null
+++ b/Functions/Example/Tests/FIRFunctionsTests.m
@@ -0,0 +1,50 @@
+// 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 XCTest;
+
+#import "FIRFunctions+Internal.h"
+#import "FIRFunctions.h"
+
+#import "FUNFakeApp.h"
+
+@interface FIRFunctionsTests : XCTestCase
+@end
+
+@implementation FIRFunctionsTests
+
+- (void)setUp {
+ [super setUp];
+}
+
+- (void)tearDown {
+ [super tearDown];
+}
+
+- (void)testURLWithName {
+ // TODO(klimt): Add this test back when we add the constructor back.
+ /*
+ id app = [[FUNFakeApp alloc] initWithProjectID:@"my-project"];
+ FIRFunctions *functions = [FIRFunctions functionsForApp:app region:@"my-region"];
+ NSString *url = [functions URLWithName:@"my-endpoint"];
+ XCTAssertEqualObjects(@"https://my-region-my-project.cloudfunctions.net/my-endpoint", url);
+ */
+
+ id app = [[FUNFakeApp alloc] initWithProjectID:@"my-project"];
+ FIRFunctions *functions = [FIRFunctions functionsForApp:app];
+ NSString *url = [functions URLWithName:@"my-endpoint"];
+ XCTAssertEqualObjects(@"https://us-central1-my-project.cloudfunctions.net/my-endpoint", url);
+}
+
+@end
diff --git a/Functions/Example/Tests/FUNSerializerTests.m b/Functions/Example/Tests/FUNSerializerTests.m
new file mode 100644
index 0000000..707c3e7
--- /dev/null
+++ b/Functions/Example/Tests/FUNSerializerTests.m
@@ -0,0 +1,240 @@
+// 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 XCTest;
+
+#import "FIRError.h"
+#import "FUNSerializer.h"
+
+@interface FUNSerializerTests : XCTestCase
+@end
+
+@implementation FUNSerializerTests
+
+- (void)setUp {
+ [super setUp];
+}
+
+- (void)tearDown {
+ [super tearDown];
+}
+
+- (void)testEncodeNull {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects([NSNull null], [serializer encode:[NSNull null]]);
+}
+
+- (void)testDecodeNull {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects([NSNull null], [serializer decode:[NSNull null] error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeInt {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects(@1, [serializer encode:@1]);
+}
+
+- (void)testDecodeInt {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(@1, [serializer decode:@1 error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeLong {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSDictionary *expected = @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"-9223372036854775800",
+ };
+ XCTAssertEqualObjects(expected, [serializer encode:@-9223372036854775800L]);
+}
+
+- (void)testDecodeLong {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSDictionary *input = @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"-9223372036854775800",
+ };
+ NSError *error = nil;
+ NSNumber *actual = [serializer decode:input error:&error];
+ XCTAssertEqualObjects(@-9223372036854775800L, actual);
+ // A naive implementation might convert a number to a double and think that's close enough.
+ // We need to make sure it's a long long for accuracy.
+ XCTAssertEqual('q', actual.objCType[0]);
+ XCTAssertNil(error);
+}
+
+- (void)testDecodeInvalidLong {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSDictionary *input = @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"-9223372036854775800 and some other junk",
+ };
+ NSError *error = nil;
+ NSNumber *actual = [serializer decode:input error:&error];
+ XCTAssertNil(actual);
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(FIRFunctionsErrorDomain, error.domain);
+ XCTAssertEqual(FIRFunctionsErrorCodeInternal, error.code);
+}
+
+- (void)testEncodeUnsignedLong {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSDictionary *expected = @{
+ @"@type" : @"type.googleapis.com/google.protobuf.UInt64Value",
+ @"value" : @"18446744073709551600",
+ };
+ XCTAssertEqualObjects(expected, [serializer encode:@18446744073709551600UL]);
+}
+
+- (void)testDecodeUnsignedLong {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSDictionary *input = @{
+ @"@type" : @"type.googleapis.com/google.protobuf.UInt64Value",
+ @"value" : @"17446744073709551688",
+ };
+ NSError *error = nil;
+ NSNumber *actual = [serializer decode:input error:&error];
+ XCTAssertEqualObjects(@17446744073709551688UL, actual);
+ // A naive NSNumberFormatter implementation will convert the number to a double and think
+ // that's close enough. We need to make sure it's an unsigned long long for accuracy.
+ XCTAssertEqual('Q', actual.objCType[0]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeDouble {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects(@1.2, [serializer encode:@1.2]);
+}
+
+- (void)testDecodeDouble {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(@1.2, [serializer decode:@1.2 error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeBool {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects(@YES, [serializer encode:@YES]);
+}
+
+- (void)testDecodeBool {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(@NO, [serializer decode:@NO error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeString {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects(@"hello", [serializer encode:@"hello"]);
+}
+
+- (void)testDecodeString {
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(@"hello", [serializer decode:@"hello" error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeArray {
+ NSArray *input = @[ @1, @"two", @[ @3, @4L ] ];
+ NSArray *expected = @[
+ @1, @"two",
+ @[
+ @3, @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"4",
+ }
+ ]
+ ];
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects(expected, [serializer encode:input]);
+}
+
+- (void)testDecodeArray {
+ NSArray *input = @[
+ @1, @"two",
+ @[
+ @3, @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"4",
+ }
+ ]
+ ];
+ NSArray *expected = @[ @1, @"two", @[ @3, @4L ] ];
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+
+ XCTAssertEqualObjects(expected, [serializer decode:input error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testEncodeMap {
+ NSDictionary *input = @{ @"foo" : @1, @"bar" : @"hello", @"baz" : @[ @3, @4L ] };
+ NSDictionary *expected = @{
+ @"foo" : @1,
+ @"bar" : @"hello",
+ @"baz" : @[
+ @3, @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"4",
+ }
+ ]
+ };
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ XCTAssertEqualObjects(expected, [serializer encode:input]);
+}
+
+- (void)testDecodeMap {
+ NSDictionary *input = @{
+ @"foo" : @1,
+ @"bar" : @"hello",
+ @"baz" : @[
+ @3, @{
+ @"@type" : @"type.googleapis.com/google.protobuf.Int64Value",
+ @"value" : @"4",
+ }
+ ]
+ };
+ NSDictionary *expected = @{ @"foo" : @1, @"bar" : @"hello", @"baz" : @[ @3, @4L ] };
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(expected, [serializer decode:input error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testDecodeUnknownType {
+ NSDictionary *input = @{@"@type" : @"unknown", @"value" : @"whatever"};
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(input, [serializer decode:input error:&error]);
+ XCTAssertNil(error);
+}
+
+- (void)testDecodeUnknownTypeWithoutValue {
+ NSDictionary *input = @{
+ @"@type" : @"unknown",
+ };
+ FUNSerializer *serializer = [[FUNSerializer alloc] init];
+ NSError *error = nil;
+ XCTAssertEqualObjects(input, [serializer decode:input error:&error]);
+ XCTAssertNil(error);
+}
+
+@end
diff --git a/Functions/Example/Tests/Tests-Info.plist b/Functions/Example/Tests/Tests-Info.plist
new file mode 100644
index 0000000..169b6f7
--- /dev/null
+++ b/Functions/Example/Tests/Tests-Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/Functions/Example/Tests/en.lproj/InfoPlist.strings b/Functions/Example/Tests/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..477b28f
--- /dev/null
+++ b/Functions/Example/Tests/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/Functions/FirebaseFunctions/FIRFunctions+Internal.h b/Functions/FirebaseFunctions/FIRFunctions+Internal.h
new file mode 100644
index 0000000..6c555f0
--- /dev/null
+++ b/Functions/FirebaseFunctions/FIRFunctions+Internal.h
@@ -0,0 +1,50 @@
+// 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/Foundation.h>
+
+#import "FIRFunctions.h"
+
+@class FIRHTTPSCallableResult;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRFunctions (Internal)
+
+/**
+ * Calls an http trigger endpoint.
+ * @param name The name of the http trigger.
+ * @param data Parameters to pass to the function. Can be anything encodable as JSON.
+ * @param completion The block to call when the request is complete.
+ */
+- (void)callFunction:(NSString *)name
+ withObject:(nullable id)data
+ completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
+ NSError *_Nullable error))completion;
+
+/**
+ * Constructs the url for an http trigger. This is exposed only for testing.
+ * @param name The name of the endpoint.
+ */
+- (NSString *)URLWithName:(NSString *)name;
+
+/**
+ * Sets the functions client to send requests to localhost instead of Firebase.
+ * For testing only.
+ */
+- (void)useLocalhost;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FIRFunctions.m b/Functions/FirebaseFunctions/FIRFunctions.m
new file mode 100644
index 0000000..274d058
--- /dev/null
+++ b/Functions/FirebaseFunctions/FIRFunctions.m
@@ -0,0 +1,247 @@
+// 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 "FIRFunctions.h"
+#import "FIRFunctions+Internal.h"
+
+#import "FIRError.h"
+#import "FIRHTTPSCallable+Internal.h"
+#import "FIRHTTPSCallable.h"
+#import "FUNContext.h"
+#import "FUNError.h"
+#import "FUNSerializer.h"
+#import "FUNUsageValidation.h"
+
+#import "FIRApp.h"
+#import "FIRAppInternal.h"
+#import "FIROptions.h"
+#import "GTMSessionFetcherService.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+NSString *const kFUNInstanceIDTokenHeader = @"Firebase-Instance-ID-Token";
+
+@interface FIRFunctions () {
+ // The network client to use for http requests.
+ GTMSessionFetcherService *_fetcherService;
+ // The projectID to use for all function references.
+ FIRApp *_app;
+ // The region to use for all function references.
+ NSString *_region;
+ // A serializer to encode/decode data and return values.
+ FUNSerializer *_serializer;
+ // A factory for getting the metadata to include with function calls.
+ FUNContextProvider *_contextProvider;
+ // For testing only. If this is set, functions will be called against localhost instead of
+ // Firebase.
+ BOOL _useLocalhost;
+}
+
+/**
+ * Initialize the Cloud Functions client with the given app and region.
+ * @param app The app for the Firebase project.
+ * @param region The region for the http trigger, such as "us-central1".
+ */
+- (id)initWithApp:(FIRApp *)app region:(NSString *)region NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation FIRFunctions
+
++ (instancetype)functions {
+ return [[self alloc] initWithApp:[FIRApp defaultApp] region:@"us-central1"];
+}
+
++ (instancetype)functionsForApp:(FIRApp *)app {
+ return [[self alloc] initWithApp:app region:@"us-central1"];
+}
+
++ (instancetype)functionsForRegion:(NSString *)region {
+ return [[self alloc] initWithApp:[FIRApp defaultApp] region:region];
+}
+
++ (instancetype)functionsForApp:(FIRApp *)app region:(NSString *)region {
+ return [[self alloc] initWithApp:app region:region];
+}
+
+- (instancetype)initWithApp:(FIRApp *)app region:(NSString *)region {
+ self = [super init];
+ if (self) {
+ if (!region) {
+ FUNThrowInvalidArgument(@"FIRFunctions region cannot be nil.");
+ }
+ _fetcherService = [[GTMSessionFetcherService alloc] init];
+ _app = app;
+ _region = [region copy];
+ _serializer = [[FUNSerializer alloc] init];
+ _contextProvider = [[FUNContextProvider alloc] initWithApp:app];
+ _useLocalhost = NO;
+ }
+ return self;
+}
+
+- (void)useLocalhost {
+ _useLocalhost = YES;
+}
+
+- (NSString *)URLWithName:(NSString *)name {
+ if (!name) {
+ FUNThrowInvalidArgument(@"FIRFunctions function name cannot be nil.");
+ }
+ NSString *projectID = _app.options.projectID;
+ if (!projectID) {
+ FUNThrowInvalidArgument(@"FIRFunctions app projectID cannot be nil.");
+ }
+ if (_useLocalhost) {
+ return [NSString stringWithFormat:@"http://localhost:5005/%@/%@/%@", projectID, _region, name];
+ }
+ return
+ [NSString stringWithFormat:@"https://%@-%@.cloudfunctions.net/%@", _region, projectID, name];
+}
+
+- (void)callFunction:(NSString *)name
+ withObject:(nullable id)data
+ completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
+ NSError *_Nullable error))completion {
+ [_contextProvider getContext:^(FUNContext *_Nullable context, NSError *_Nullable error) {
+ if (error) {
+ if (completion) {
+ completion(nil, error);
+ }
+ return;
+ }
+ return [self callFunction:name withObject:data context:context completion:completion];
+ }];
+}
+
+- (void)callFunction:(NSString *)name
+ withObject:(nullable id)data
+ context:(FUNContext *)context
+ completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
+ NSError *_Nullable error))completion {
+ GTMSessionFetcher *fetcher = [_fetcherService fetcherWithURLString:[self URLWithName:name]];
+
+ NSMutableDictionary *body = [NSMutableDictionary dictionary];
+ // Encode the data in the body.
+ if (!data) {
+ data = [NSNull null];
+ }
+ id encoded = [_serializer encode:data];
+ if (!encoded) {
+ FUNThrowInvalidArgument(@"FIRFunctions data encoded as nil. This should not happen.");
+ }
+ body[@"data"] = encoded;
+
+ NSError *error = nil;
+ NSData *payload = [NSJSONSerialization dataWithJSONObject:body options:0 error:&error];
+ if (error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(nil, error);
+ });
+ }
+ return;
+ }
+ fetcher.bodyData = payload;
+
+ // Set the headers.
+ [fetcher setRequestValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
+ if (context.authToken) {
+ NSString *value = [NSString stringWithFormat:@"Bearer %@", context.authToken];
+ [fetcher setRequestValue:value forHTTPHeaderField:@"Authorization"];
+ }
+ if (context.instanceIDToken) {
+ [fetcher setRequestValue:context.instanceIDToken forHTTPHeaderField:kFUNInstanceIDTokenHeader];
+ }
+
+ // Override normal security rules if this is a local test.
+ if (_useLocalhost) {
+ fetcher.allowLocalhostRequest = YES;
+ fetcher.allowedInsecureSchemes = @[ @"http" ];
+ }
+
+ FUNSerializer *serializer = _serializer;
+ [fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) {
+ // If there was an HTTP error, convert it to our own error domain.
+ if (error) {
+ if ([error.domain isEqualToString:kGTMSessionFetcherStatusDomain]) {
+ error = FUNErrorForResponse(error.code, data, serializer);
+ }
+ } else {
+ // If there wasn't an HTTP error, see if there was an error in the body.
+ error = FUNErrorForResponse(200, data, serializer);
+ }
+ // If there was an error, report it to the user and stop.
+ if (error) {
+ if (completion) {
+ completion(nil, error);
+ }
+ return;
+ }
+
+ id responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
+ if (error) {
+ if (completion) {
+ completion(nil, error);
+ }
+ return;
+ }
+ if (![responseJSON isKindOfClass:[NSDictionary class]]) {
+ NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"Response was not a dictionary."};
+ error = [NSError errorWithDomain:FIRFunctionsErrorDomain
+ code:FIRFunctionsErrorCodeInternal
+ userInfo:userInfo];
+ if (completion) {
+ completion(nil, error);
+ }
+ return;
+ }
+ id dataJSON = responseJSON[@"data"];
+ // TODO(klimt): Allow "result" instead of "data" for now, for backwards compatibility.
+ if (!dataJSON) {
+ dataJSON = responseJSON[@"result"];
+ }
+ if (!dataJSON) {
+ NSDictionary *userInfo =
+ @{NSLocalizedDescriptionKey : @"Response did not include data field."};
+ error = [NSError errorWithDomain:FIRFunctionsErrorDomain
+ code:FIRFunctionsErrorCodeInternal
+ userInfo:userInfo];
+ if (completion) {
+ completion(nil, error);
+ }
+ return;
+ }
+ id resultData = [serializer decode:dataJSON error:&error];
+ if (error) {
+ if (completion) {
+ completion(nil, error);
+ }
+ return;
+ }
+ id result = [[FIRHTTPSCallableResult alloc] initWithData:resultData];
+ if (completion) {
+ // If there's no result field, this will return nil, which is fine.
+ completion(result, nil);
+ }
+ }];
+}
+
+- (FIRHTTPSCallable *)HTTPSCallableWithName:(NSString *)name {
+ return [[FIRHTTPSCallable alloc] initWithFunctions:self name:name];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FIRHTTPSCallable+Internal.h b/Functions/FirebaseFunctions/FIRHTTPSCallable+Internal.h
new file mode 100644
index 0000000..0a8dae1
--- /dev/null
+++ b/Functions/FirebaseFunctions/FIRHTTPSCallable+Internal.h
@@ -0,0 +1,46 @@
+// 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/Foundation.h>
+
+#import "FIRHTTPSCallable.h"
+
+@class FIRFunctions;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRHTTPSCallableResult (Internal)
+
+/**
+ * Initializes a callable result.
+ *
+ * @param result The data to wrap.
+ */
+- (instancetype)initWithData:(id)result;
+
+@end
+
+@interface FIRHTTPSCallable (Internal)
+
+/**
+ * Initializes a reference to the given http trigger.
+ *
+ * @param functionsClient The functions client to use for making network requests.
+ * @param name The name of the http trigger.
+ */
+- (instancetype)initWithFunctions:(FIRFunctions *)functionsClient name:(NSString *)name;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FIRHTTPSCallable.m b/Functions/FirebaseFunctions/FIRHTTPSCallable.m
new file mode 100644
index 0000000..2979ca5
--- /dev/null
+++ b/Functions/FirebaseFunctions/FIRHTTPSCallable.m
@@ -0,0 +1,71 @@
+// 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 "FIRHTTPSCallable.h"
+#import "FIRHTTPSCallable+Internal.h"
+
+#import "FIRFunctions+Internal.h"
+#import "FUNUsageValidation.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRHTTPSCallableResult
+
+- (instancetype)initWithData:(id)data {
+ self = [super init];
+ if (self) {
+ _data = data;
+ }
+ return self;
+}
+
+@end
+
+@interface FIRHTTPSCallable () {
+ // The functions client to use for making calls.
+ FIRFunctions *_functions;
+ // The name of the http endpoint this reference refers to.
+ NSString *_name;
+}
+
+@end
+
+@implementation FIRHTTPSCallable
+
+- (instancetype)initWithFunctions:(FIRFunctions *)functions name:(NSString *)name {
+ self = [super init];
+ if (self) {
+ if (!name) {
+ FUNThrowInvalidArgument(@"FIRHTTPSCallable name cannot be nil.");
+ }
+ _name = [name copy];
+ _functions = functions;
+ }
+ return self;
+}
+
+- (void)callWithCompletion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
+ NSError *_Nullable error))completion {
+ [self callWithObject:nil completion:completion];
+}
+
+- (void)callWithObject:(nullable id)data
+ completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
+ NSError *_Nullable error))completion {
+ [_functions callFunction:_name withObject:data completion:completion];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNContext.h b/Functions/FirebaseFunctions/FUNContext.h
new file mode 100644
index 0000000..5cbc474
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNContext.h
@@ -0,0 +1,44 @@
+//
+// 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/Foundation.h>
+
+@class FIRApp;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * FUNContext is a helper class for gathering metadata for a function call.
+ */
+@interface FUNContext : NSObject
+- (id)init NS_UNAVAILABLE;
+@property(nonatomic, copy, nullable, readonly) NSString *authToken;
+@property(nonatomic, copy, nullable, readonly) NSString *instanceIDToken;
+@end
+
+/**
+ * A FUNContextProvider gathers metadata and creats a FUNContext.
+ */
+@interface FUNContextProvider : NSObject
+
+- (id)init NS_UNAVAILABLE;
+
+- (instancetype)initWithApp:(FIRApp *)app NS_DESIGNATED_INITIALIZER;
+
+- (void)getContext:(void (^)(FUNContext *_Nullable context, NSError *_Nullable error))completion;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNContext.m b/Functions/FirebaseFunctions/FUNContext.m
new file mode 100644
index 0000000..890b5bf
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNContext.m
@@ -0,0 +1,87 @@
+//
+// 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 "FUNContext.h"
+
+#import "FIRApp.h"
+#import "FIRAppInternal.h"
+#import "FUNInstanceIDProxy.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FUNContext ()
+
+- (instancetype)initWithAuthToken:(NSString *_Nullable)authToken
+ instanceIDToken:(NSString *_Nullable)instanceIDToken NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation FUNContext
+
+- (instancetype)initWithAuthToken:(NSString *_Nullable)authToken
+ instanceIDToken:(NSString *_Nullable)instanceIDToken {
+ self = [super init];
+ if (self) {
+ _authToken = [authToken copy];
+ _instanceIDToken = [instanceIDToken copy];
+ }
+ return self;
+}
+
+@end
+
+@interface FUNContextProvider () {
+ FIRApp *_app;
+ FUNInstanceIDProxy *_instanceIDProxy;
+}
+@end
+
+@implementation FUNContextProvider
+
+- (instancetype)initWithApp:(FIRApp *)app {
+ self = [super init];
+ if (self) {
+ _app = app;
+ _instanceIDProxy = [[FUNInstanceIDProxy alloc] init];
+ }
+ return self;
+}
+
+// This is broken out so it can be mocked for tests.
+- (NSString *)instanceIDToken {
+ return [_instanceIDProxy token];
+}
+
+- (void)getContext:(void (^)(FUNContext *_Nullable context, NSError *_Nullable error))completion {
+ // Get the auth token.
+ [_app getTokenForcingRefresh:NO
+ withCallback:^(NSString *_Nullable token, NSError *_Nullable error) {
+ if (error) {
+ completion(nil, error);
+ return;
+ }
+
+ // Get the instance id token.
+ NSString *_Nullable instanceIDToken = [self instanceIDToken];
+
+ FUNContext *context = [[FUNContext alloc] initWithAuthToken:token
+ instanceIDToken:instanceIDToken];
+ completion(context, nil);
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNError.h b/Functions/FirebaseFunctions/FUNError.h
new file mode 100644
index 0000000..d66a814
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNError.h
@@ -0,0 +1,34 @@
+//
+// 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/Foundation.h>
+
+@class FUNSerializer;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Takes an HTTP status code and optional body and returns a corresponding NSError.
+ * If an explicit error is encoded in the JSON body, it will be used.
+ * Otherwise, uses the standard HTTP status code -> error mapping defined in:
+ * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+ * @param status An HTTP status code.
+ * @param body Optional body of the HTTP response.
+ * @param serializer A serializer to use to decode the details in the error response.
+ * @return The corresponding error.
+ */
+NSError *FUNErrorForResponse(NSInteger status, NSData *_Nullable body, FUNSerializer *serializer);
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNError.m b/Functions/FirebaseFunctions/FUNError.m
new file mode 100644
index 0000000..abe0287
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNError.m
@@ -0,0 +1,189 @@
+//
+// 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 "FUNError.h"
+#import "FIRError.h"
+
+#import "FUNSerializer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+NSString *const FIRFunctionsErrorDomain = @"com.firebase.functions";
+NSString *const FIRFunctionsErrorDetailsKey = @"details";
+
+/**
+ * Takes an HTTP status code and returns the corresponding FIRFunctionsErrorCode error code.
+ * This is the standard HTTP status code -> error mapping defined in:
+ * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+ * @param status An HTTP status code.
+ * @return The corresponding error code, or FIRFunctionsErrorCodeUnknown if none.
+ */
+FIRFunctionsErrorCode FIRFunctionsErrorCodeForHTTPStatus(NSInteger status) {
+ switch (status) {
+ case 200:
+ return FIRFunctionsErrorCodeOK;
+ case 400:
+ return FIRFunctionsErrorCodeInvalidArgument;
+ case 401:
+ return FIRFunctionsErrorCodeUnauthenticated;
+ case 403:
+ return FIRFunctionsErrorCodePermissionDenied;
+ case 404:
+ return FIRFunctionsErrorCodeNotFound;
+ case 409:
+ return FIRFunctionsErrorCodeAborted;
+ case 429:
+ return FIRFunctionsErrorCodeResourceExhausted;
+ case 499:
+ return FIRFunctionsErrorCodeCancelled;
+ case 500:
+ return FIRFunctionsErrorCodeInternal;
+ case 501:
+ return FIRFunctionsErrorCodeUnimplemented;
+ case 503:
+ return FIRFunctionsErrorCodeUnavailable;
+ case 504:
+ return FIRFunctionsErrorCodeDeadlineExceeded;
+ }
+ return FIRFunctionsErrorCodeInternal;
+}
+
+/**
+ * Takes the name of an error code and returns the enum value for it.
+ * @param name An error name.
+ * @return The error code with this name, or FIRFunctionsErrorCodeUnknown if none.
+ */
+FIRFunctionsErrorCode FIRFunctionsErrorCodeForName(NSString *name) {
+ static NSDictionary<NSString *, NSNumber *> *errors;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ errors = @{
+ @"OK" : @(FIRFunctionsErrorCodeOK),
+ @"CANCELLED" : @(FIRFunctionsErrorCodeCancelled),
+ @"UNKNOWN" : @(FIRFunctionsErrorCodeUnknown),
+ @"INVALID_ARGUMENT" : @(FIRFunctionsErrorCodeInvalidArgument),
+ @"DEADLINE_EXCEEDED" : @(FIRFunctionsErrorCodeDeadlineExceeded),
+ @"NOT_FOUND" : @(FIRFunctionsErrorCodeNotFound),
+ @"ALREADY_EXISTS" : @(FIRFunctionsErrorCodeAlreadyExists),
+ @"PERMISSION_DENIED" : @(FIRFunctionsErrorCodePermissionDenied),
+ @"RESOURCE_EXHAUSTED" : @(FIRFunctionsErrorCodeResourceExhausted),
+ @"FAILED_PRECONDITION" : @(FIRFunctionsErrorCodeFailedPrecondition),
+ @"ABORTED" : @(FIRFunctionsErrorCodeAborted),
+ @"OUT_OF_RANGE" : @(FIRFunctionsErrorCodeOutOfRange),
+ @"UNIMPLEMENTED" : @(FIRFunctionsErrorCodeUnimplemented),
+ @"INTERNAL" : @(FIRFunctionsErrorCodeInternal),
+ @"UNAVAILABLE" : @(FIRFunctionsErrorCodeUnavailable),
+ @"DATA_LOSS" : @(FIRFunctionsErrorCodeDataLoss),
+ @"UNAUTHENTICATED" : @(FIRFunctionsErrorCodeUnauthenticated),
+ };
+ });
+ NSNumber *code = errors[name];
+ if (code) {
+ return code.intValue;
+ }
+ return FIRFunctionsErrorCodeInternal;
+}
+
+/**
+ * Takes a FIRFunctionsErrorCode and returns an English description of it.
+ * @param code An error code.
+ * @return A description of the code, or "UNKNOWN" if none.
+ */
+NSString *FUNDescriptionForErrorCode(FIRFunctionsErrorCode code) {
+ switch (code) {
+ case FIRFunctionsErrorCodeOK:
+ return @"OK";
+ case FIRFunctionsErrorCodeCancelled:
+ return @"CANCELLED";
+ case FIRFunctionsErrorCodeUnknown:
+ return @"UNKNOWN";
+ case FIRFunctionsErrorCodeInvalidArgument:
+ return @"INVALID ARGUMENT";
+ case FIRFunctionsErrorCodeDeadlineExceeded:
+ return @"DEADLINE EXCEEDED";
+ case FIRFunctionsErrorCodeNotFound:
+ return @"NOT FOUND";
+ case FIRFunctionsErrorCodeAlreadyExists:
+ return @"ALREADY EXISTS";
+ case FIRFunctionsErrorCodePermissionDenied:
+ return @"PERMISSION DENIED";
+ case FIRFunctionsErrorCodeResourceExhausted:
+ return @"RESOURCE EXHAUSTED";
+ case FIRFunctionsErrorCodeFailedPrecondition:
+ return @"FAILED PRECONDITION";
+ case FIRFunctionsErrorCodeAborted:
+ return @"ABORTED";
+ case FIRFunctionsErrorCodeOutOfRange:
+ return @"OUT OF RANGE";
+ case FIRFunctionsErrorCodeUnimplemented:
+ return @"UNIMPLEMENTED";
+ case FIRFunctionsErrorCodeInternal:
+ return @"INTERNAL";
+ case FIRFunctionsErrorCodeUnavailable:
+ return @"UNAVAILABLE";
+ case FIRFunctionsErrorCodeDataLoss:
+ return @"DATA LOSS";
+ case FIRFunctionsErrorCodeUnauthenticated:
+ return @"UNAUTHENTICATED";
+ }
+ return @"UNKNOWN";
+}
+
+NSError *FUNErrorForResponse(NSInteger status, NSData *_Nullable body, FUNSerializer *serializer) {
+ // Start with reasonable defaults from the status code.
+ FIRFunctionsErrorCode code = FIRFunctionsErrorCodeForHTTPStatus(status);
+ NSString *description = FUNDescriptionForErrorCode(code);
+ id details = nil;
+
+ // Then look through the body for explicit details.
+ if (body) {
+ NSError *parseError = nil;
+ id json = [NSJSONSerialization JSONObjectWithData:body options:0 error:&parseError];
+ if (!parseError && [json isKindOfClass:[NSDictionary class]]) {
+ id errorDetails = json[@"error"];
+ if ([errorDetails isKindOfClass:[NSDictionary class]]) {
+ if ([errorDetails[@"status"] isKindOfClass:[NSString class]]) {
+ code = FIRFunctionsErrorCodeForName(errorDetails[@"status"]);
+ // The default description needs to be updated for the new code.
+ description = FUNDescriptionForErrorCode(code);
+ }
+ if ([errorDetails[@"message"] isKindOfClass:[NSString class]]) {
+ description = (NSString *)errorDetails[@"message"];
+ }
+ details = errorDetails[@"details"];
+ if (details) {
+ NSError *decodeError = nil;
+ details = [serializer decode:details error:&decodeError];
+ // Just ignore the details if there an error decoding them.
+ }
+ }
+ }
+ }
+
+ if (code == FIRFunctionsErrorCodeOK) {
+ // Technically, there's an edge case where a developer could explicitly return an error code of
+ // OK, and we will treat it as success, but that seems reasonable.
+ return nil;
+ }
+
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+ userInfo[NSLocalizedDescriptionKey] = description;
+ if (details) {
+ userInfo[FIRFunctionsErrorDetailsKey] = details;
+ }
+ return [NSError errorWithDomain:FIRFunctionsErrorDomain code:code userInfo:userInfo];
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNInstanceIDProxy.h b/Functions/FirebaseFunctions/FUNInstanceIDProxy.h
new file mode 100644
index 0000000..17ec9ef
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNInstanceIDProxy.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+// Note: This file is forked from FIRMessagingInstanceIDProxy.h
+
+#import <Foundation/Foundation.h>
+
+/**
+ * FirebaseFunctions cannot always depend on FIRInstanceID directly, due to how it is
+ * packaged. To make it easier to make calls to FIRInstanceID, this proxy class, will provide
+ * method names duplicated from FIRInstanceID, while using reflection-based called to proxy
+ * the requests.
+ */
+@interface FUNInstanceIDProxy : NSObject
+- (nullable NSString *)token;
+@end
diff --git a/Functions/FirebaseFunctions/FUNInstanceIDProxy.m b/Functions/FirebaseFunctions/FUNInstanceIDProxy.m
new file mode 100644
index 0000000..f89ec98
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNInstanceIDProxy.m
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+// Note: This is forked from FIRMessagingInstanceIDProxy.m
+
+#import "FUNInstanceIDProxy.h"
+
+@implementation FUNInstanceIDProxy
+
++ (nonnull instancetype)instanceIDProxy {
+ static id proxyInstanceID = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ Class instanceIDClass = NSClassFromString(@"FIRInstanceID");
+ if (!instanceIDClass) {
+ proxyInstanceID = nil;
+ return;
+ }
+ SEL instanceIDSelector = NSSelectorFromString(@"instanceID");
+ if (![instanceIDClass respondsToSelector:instanceIDSelector]) {
+ proxyInstanceID = nil;
+ return;
+ }
+ IMP instanceIDImp = [instanceIDClass methodForSelector:instanceIDSelector];
+ id (*instanceIDFunc)(id, SEL) = (void *)instanceIDImp;
+ proxyInstanceID = instanceIDFunc(instanceIDClass, instanceIDSelector);
+ });
+ return (FUNInstanceIDProxy *)proxyInstanceID;
+}
+
+#pragma mark - Tokens
+
+- (nullable NSString *)token {
+ id proxy = [[self class] instanceIDProxy];
+ SEL getTokenSelector = NSSelectorFromString(@"token");
+ if (![proxy respondsToSelector:getTokenSelector]) {
+ return nil;
+ }
+ IMP getTokenIMP = [proxy methodForSelector:getTokenSelector];
+ NSString *(*getToken)(id, SEL) = (void *)getTokenIMP;
+ return getToken(proxy, getTokenSelector);
+}
+
+@end
diff --git a/Functions/FirebaseFunctions/FUNSerializer.h b/Functions/FirebaseFunctions/FUNSerializer.h
new file mode 100644
index 0000000..598a2a1
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNSerializer.h
@@ -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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FUNSerializer : NSObject
+
+/**
+ * Converts raw Objective-C types into JSON objects.
+ */
+- (id)encode:(id)object;
+
+/**
+ * Converts objects in JSON to Objective-C types.
+ */
+- (id)decode:(id)object error:(NSError **)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNSerializer.m b/Functions/FirebaseFunctions/FUNSerializer.m
new file mode 100644
index 0000000..682f981
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNSerializer.m
@@ -0,0 +1,231 @@
+// 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 "FUNSerializer.h"
+
+#import "FIRError.h"
+#import "FUNUsageValidation.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+static NSString *const kLongType = @"type.googleapis.com/google.protobuf.Int64Value";
+static NSString *const kUnsignedLongType = @"type.googleapis.com/google.protobuf.UInt64Value";
+static NSString *const kDateType = @"type.googleapis.com/google.protobuf.Timestamp";
+
+@interface FUNSerializer () {
+ NSDateFormatter *_dateFormatter;
+}
+@end
+
+@implementation FUNSerializer
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _dateFormatter = [[NSDateFormatter alloc] init];
+ _dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+ _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
+ }
+ return self;
+}
+
+- (id)encodeNumber:(NSNumber *)number {
+ // Recover the underlying type of the number, using the method described here:
+ // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber
+ const char *cType = [number objCType];
+
+ // Type Encoding values taken from
+ // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/
+ // Articles/ocrtTypeEncodings.html
+ switch (cType[0]) {
+ case 'q':
+ // "long long" might be larger than JS supports, so make it a string.
+ return @{
+ @"@type" : kLongType,
+ @"value" : [NSString stringWithFormat:@"%@", number],
+ };
+ case 'Q':
+ // "unsigned long long" might be larger than JS supports, so make it a string.
+ return @{
+ @"@type" : kUnsignedLongType,
+ @"value" : [NSString stringWithFormat:@"%@", number],
+ };
+
+ case 'i':
+ case 's':
+ case 'l':
+ case 'I':
+ case 'S':
+ // If it's an integer that isn't too long, so just use the number.
+ return number;
+
+ case 'f':
+ case 'd':
+ // It's a float/double that's not too large.
+ return number;
+
+ case 'B':
+ case 'c':
+ case 'C':
+ // Boolean values are weird.
+ //
+ // On arm64, objCType of a BOOL-valued NSNumber will be "c", even though @encode(BOOL)
+ // returns "B". "c" is the same as @encode(signed char). Unfortunately this means that
+ // legitimate usage of signed chars is impossible, but this should be rare.
+ //
+ // Just return Boolean values as-is.
+ return number;
+
+ default:
+ // All documented codes should be handled above, so this shouldn't happen.
+ FUNThrowInvalidArgument(@"Unknown NSNumber objCType %s on %@", cType, number);
+ }
+}
+
+- (id)encode:(id)object {
+ if ([object isEqual:[NSNull null]]) {
+ return object;
+ }
+ if ([object isKindOfClass:[NSNumber class]]) {
+ return [self encodeNumber:object];
+ }
+ if ([object isKindOfClass:[NSString class]]) {
+ return object;
+ }
+ if ([object isKindOfClass:[NSDictionary class]]) {
+ NSMutableDictionary *encoded = [NSMutableDictionary dictionary];
+ [object
+ enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
+ encoded[key] = [self encode:obj];
+ }];
+ return encoded;
+ }
+ if ([object isKindOfClass:[NSArray class]]) {
+ NSMutableArray *encoded = [NSMutableArray arrayWithCapacity:[object count]];
+ for (id obj in object) {
+ [encoded addObject:[self encode:obj]];
+ }
+ return encoded;
+ }
+ // TODO(klimt): Add this back when we support NSDate.
+ /*
+ if ([object isKindOfClass:[NSDate class]]) {
+ NSString *iso8601 = [_dateFormatter stringFromDate:object];
+ return @{
+ @"@type" : kDateType,
+ @"value" : iso8601,
+ };
+ }
+ */
+ FUNThrowInvalidArgument(@"Unsupported type: %@ for value %@", NSStringFromClass([object class]),
+ object);
+}
+
+NSError *FUNInvalidNumberError(id value, id wrapped) {
+ NSString *description = [NSString stringWithFormat:@"Invalid number: %@ for %@", value, wrapped];
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey : description,
+ };
+ return [NSError errorWithDomain:FIRFunctionsErrorDomain
+ code:FIRFunctionsErrorCodeInternal
+ userInfo:userInfo];
+}
+
+- (id)decodeWrappedType:(NSDictionary *)wrapped error:(NSError **)error {
+ NSAssert(error, @"error must not be nil");
+ NSString *type = wrapped[@"@type"];
+ NSString *value = wrapped[@"value"];
+ if (!value) {
+ return nil;
+ }
+ if ([type isEqualToString:kLongType]) {
+ NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
+ NSNumber *n = [formatter numberFromString:value];
+ if (!n) {
+ *error = FUNInvalidNumberError(value, wrapped);
+ return nil;
+ }
+ return n;
+ } else if ([type isEqualToString:kUnsignedLongType]) {
+ // NSNumber formatter doesn't handle unsigned long long, so we have to parse it.
+ const char *str = value.UTF8String;
+ char *end = NULL;
+ unsigned long long n = strtoull(str, &end, 10);
+ if (errno == ERANGE) {
+ // This number was actually too big for an unsigned long long.
+ *error = FUNInvalidNumberError(value, wrapped);
+ return nil;
+ }
+ if (*end) {
+ // The whole string wasn't parsed.
+ *error = FUNInvalidNumberError(value, wrapped);
+ return nil;
+ }
+ return @(n);
+ }
+ return nil;
+}
+
+- (id)decode:(id)object error:(NSError **)error {
+ NSAssert(error, @"error must not be nil");
+ if ([object isKindOfClass:[NSDictionary class]]) {
+ if (object[@"@type"]) {
+ id result = [self decodeWrappedType:object error:error];
+ if (*error) {
+ return nil;
+ }
+ if (result) {
+ return result;
+ }
+ // Treat unknown types as dictionaries, so we don't crash old clients when we add types.
+ }
+ NSMutableDictionary *decoded = [NSMutableDictionary dictionary];
+ __block NSError *decodeError = nil;
+ [object
+ enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
+ id decodedItem = [self decode:obj error:&decodeError];
+ if (decodeError) {
+ *stop = YES;
+ return;
+ }
+ decoded[key] = decodedItem;
+ }];
+ if (decodeError) {
+ *error = decodeError;
+ return nil;
+ }
+ return decoded;
+ }
+ if ([object isKindOfClass:[NSArray class]]) {
+ NSMutableArray *result = [NSMutableArray arrayWithCapacity:[object count]];
+ for (id obj in object) {
+ id decoded = [self decode:obj error:error];
+ if (*error) {
+ return nil;
+ }
+ [result addObject:decoded];
+ }
+ return result;
+ }
+ if ([object isKindOfClass:[NSNumber class]] || [object isKindOfClass:[NSString class]] ||
+ [object isEqual:[NSNull null]]) {
+ return object;
+ }
+ FUNThrowInvalidArgument(@"Unsupported type: %@ for value %@", NSStringFromClass([object class]),
+ object);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNUsageValidation.h b/Functions/FirebaseFunctions/FUNUsageValidation.h
new file mode 100644
index 0000000..17b1c4f
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNUsageValidation.h
@@ -0,0 +1,38 @@
+// 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/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Helper for creating a general exception for invalid usage of an API. */
+NSException *FUNInvalidUsage(NSString *exceptionName, NSString *format, ...);
+
+/**
+ * Macro to throw exceptions in response to API usage errors. Avoids the lint warning you usually
+ * get when using @throw and (unlike a function) doesn't trigger warnings about not all codepaths
+ * returning a value.
+ *
+ * Exceptions should only be used for programmer errors made by consumers of the SDK, e.g.
+ * invalid method arguments.
+ *
+ * For recoverable runtime errors, use NSError**.
+ * For internal programming errors, use FSTFail().
+ */
+#define FUNThrowInvalidArgument(format, ...) \
+ do { \
+ @throw FUNInvalidUsage(@"FIRInvalidArgumentException", format, ##__VA_ARGS__); \
+ } while (0)
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/FUNUsageValidation.m b/Functions/FirebaseFunctions/FUNUsageValidation.m
new file mode 100644
index 0000000..a50f525
--- /dev/null
+++ b/Functions/FirebaseFunctions/FUNUsageValidation.m
@@ -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 "FUNUsageValidation.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+NSException *FUNInvalidUsage(NSString *exceptionName, NSString *format, ...) {
+ va_list arg_list;
+ va_start(arg_list, format);
+ NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
+ va_end(arg_list);
+
+ return [[NSException alloc] initWithName:exceptionName reason:formattedString userInfo:nil];
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/Public/FIRError.h b/Functions/FirebaseFunctions/Public/FIRError.h
new file mode 100644
index 0000000..3048dee
--- /dev/null
+++ b/Functions/FirebaseFunctions/Public/FIRError.h
@@ -0,0 +1,91 @@
+// 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/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+// The error domain for codes in the FIRFunctionsErrorCode enum.
+FOUNDATION_EXPORT NSString *const FIRFunctionsErrorDomain NS_SWIFT_NAME(FunctionsErrorDomain);
+
+// The key for finding error details in the NSError userInfo.
+FOUNDATION_EXPORT NSString *const FIRFunctionsErrorDetailsKey
+ NS_SWIFT_NAME(FunctionsErrorDetailsKey);
+
+/**
+ * The set of error status codes that can be returned from a Callable HTTPS tigger. These are the
+ * canonical error codes for Google APIs, as documented here:
+ * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto#L26
+ */
+typedef NS_ENUM(NSInteger, FIRFunctionsErrorCode) {
+ /** The operation completed successfully. */
+ FIRFunctionsErrorCodeOK = 0,
+ /** The operation was cancelled (typically by the caller). */
+ FIRFunctionsErrorCodeCancelled = 1,
+ /** Unknown error or an error from a different error domain. */
+ FIRFunctionsErrorCodeUnknown = 2,
+ /**
+ * Client specified an invalid argument. Note that this differs from `FailedPrecondition`.
+ * `InvalidArgument` indicates arguments that are problematic regardless of the state of the
+ * system (e.g., an invalid field name).
+ */
+ FIRFunctionsErrorCodeInvalidArgument = 3,
+ /**
+ * Deadline expired before operation could complete. For operations that change the state of the
+ * system, this error may be returned even if the operation has completed successfully. For
+ * example, a successful response from a server could have been delayed long enough for the
+ * deadline to expire.
+ */
+ FIRFunctionsErrorCodeDeadlineExceeded = 4,
+ /** Some requested document was not found. */
+ FIRFunctionsErrorCodeNotFound = 5,
+ /** Some document that we attempted to create already exists. */
+ FIRFunctionsErrorCodeAlreadyExists = 6,
+ /** The caller does not have permission to execute the specified operation. */
+ FIRFunctionsErrorCodePermissionDenied = 7,
+ /**
+ * Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system
+ * is out of space.
+ */
+ FIRFunctionsErrorCodeResourceExhausted = 8,
+ /**
+ * Operation was rejected because the system is not in a state required for the operation's
+ * execution.
+ */
+ FIRFunctionsErrorCodeFailedPrecondition = 9,
+ /**
+ * The operation was aborted, typically due to a concurrency issue like transaction aborts, etc.
+ */
+ FIRFunctionsErrorCodeAborted = 10,
+ /** Operation was attempted past the valid range. */
+ FIRFunctionsErrorCodeOutOfRange = 11,
+ /** Operation is not implemented or not supported/enabled. */
+ FIRFunctionsErrorCodeUnimplemented = 12,
+ /**
+ * Internal errors. Means some invariant expected by underlying system has been broken. If you
+ * see one of these errors, something is very broken.
+ */
+ FIRFunctionsErrorCodeInternal = 13,
+ /**
+ * The service is currently unavailable. This is a most likely a transient condition and may be
+ * corrected by retrying with a backoff.
+ */
+ FIRFunctionsErrorCodeUnavailable = 14,
+ /** Unrecoverable data loss or corruption. */
+ FIRFunctionsErrorCodeDataLoss = 15,
+ /** The request does not have valid authentication credentials for the operation. */
+ FIRFunctionsErrorCodeUnauthenticated = 16,
+};
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/Public/FIRFunctions.h b/Functions/FirebaseFunctions/Public/FIRFunctions.h
new file mode 100644
index 0000000..d01175c
--- /dev/null
+++ b/Functions/FirebaseFunctions/Public/FIRFunctions.h
@@ -0,0 +1,66 @@
+// 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/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class FIRApp;
+@class FIRHTTPSCallable;
+
+/**
+ * `FIRFunctions` is the client for Cloud Functions for a Firebase project.
+ */
+NS_SWIFT_NAME(Functions)
+@interface FIRFunctions : NSObject
+
+- (id)init NS_UNAVAILABLE;
+
+/**
+ * Creates a Cloud Functions client with the default app.
+ */
++ (instancetype)functions NS_SWIFT_NAME(functions());
+
+/**
+ * Creates a Cloud Functions client with the given app.
+ * @param app The app for the Firebase project.
+ */
++ (instancetype)functionsForApp:(FIRApp *)app NS_SWIFT_NAME(functions(app:));
+
+/**
+ * Creates a Cloud Functions client with the default app and given region.
+ * @param region The region for the http trigger, such as "us-central1".
+ */
+// + (instancetype)functionsForRegion:(NSString *)region NS_SWIFT_NAME(functions(region:));
+
+/**
+ * Creates a Cloud Functions client with the given app and region.
+ * @param app The app for the Firebase project.
+ * @param region The region for the http trigger, such as "us-central1".
+ */
+// clang-format off
+// because it incorrectly breaks this NS_SWIFT_NAME.
+// + (instancetype)functionsForApp:(FIRApp *)app
+// region:(NSString *)region NS_SWIFT_NAME(functions(app:region:));
+// clang-format on
+
+/**
+ * Creates a reference to the Callable HTTPS trigger with the given name.
+ * @param name The name of the Callable HTTPS trigger.
+ */
+- (FIRHTTPSCallable *)HTTPSCallableWithName:(NSString *)name NS_SWIFT_NAME(httpsCallable(_:));
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/FirebaseFunctions/Public/FIRHTTPSCallable.h b/Functions/FirebaseFunctions/Public/FIRHTTPSCallable.h
new file mode 100644
index 0000000..9298dda
--- /dev/null
+++ b/Functions/FirebaseFunctions/Public/FIRHTTPSCallable.h
@@ -0,0 +1,93 @@
+// 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/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * A `FIRHTTPSCallableResult` contains the result of calling a `FIRHTTPSCallable`.
+ */
+NS_SWIFT_NAME(HTTPSCallableResult)
+@interface FIRHTTPSCallableResult : NSObject
+
+- (id)init NS_UNAVAILABLE;
+
+/**
+ * The data that was returned from the Callable HTTPS trigger.
+ *
+ * The data is in the form of native objects. For example, if your trigger returned an
+ * array, this object would be an NSArray. If your trigger returned a JavaScript object with
+ * keys and values, this object would be an NSDictionary.
+ */
+@property(nonatomic, strong, readonly) id data;
+
+@end
+
+/**
+ * A `FIRHTTPSCallable` is reference to a particular Callable HTTPS trigger in Cloud Functions.
+ */
+NS_SWIFT_NAME(HTTPSCallable)
+@interface FIRHTTPSCallable : NSObject
+
+- (id)init NS_UNAVAILABLE;
+
+/**
+ * Executes this Callable HTTPS trigger asynchronously without any parameters.
+ *
+ * The request to the Cloud Functions backend made by this method automatically includes a
+ * Firebase Instance ID token to identify the app instance. If a user is logged in with Firebase
+ * Auth, an auth ID token for the user is also automatically included.
+ *
+ * Firebase Instance ID sends data to the Firebase backend periodically to collect information
+ * regarding the app instance. To stop this, see `[FIRInstanceID deleteIDWithHandler:]`. It
+ * resumes with a new Instance ID the next time you call this method.
+ *
+ * @param completion The block to call when the HTTPS request has completed.
+ */
+- (void)callWithCompletion:
+ (void (^)(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error))completion
+ NS_SWIFT_NAME(call(completion:));
+
+/**
+ * Executes this Callable HTTPS trigger asynchronously.
+ *
+ * The data passed into the trigger can be any of the following types:
+ * * NSNull
+ * * NSString
+ * * NSNumber
+ * * NSArray<id>, where the contained objects are also one of these types.
+ * * NSDictionary<NSString, id>, where the values are also one of these types.
+ *
+ * The request to the Cloud Functions backend made by this method automatically includes a
+ * Firebase Instance ID token to identify the app instance. If a user is logged in with Firebase
+ * Auth, an auth ID token for the user is also automatically included.
+ *
+ * Firebase Instance ID sends data to the Firebase backend periodically to collect information
+ * regarding the app instance. To stop this, see `[FIRInstanceID deleteIDWithHandler:]`. It
+ * resumes with a new Instance ID the next time you call this method.
+ *
+ * @param data Parameters to pass to the trigger.
+ * @param completion The block to call when the HTTPS request has completed.
+ */
+// clang-format off
+// because it incorrectly breaks this NS_SWIFT_NAME.
+- (void)callWithObject:(nullable id)data
+ completion:(void (^)(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error))completion
+ NS_SWIFT_NAME(call(_:completion:));
+// clang-format on
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Functions/README.md b/Functions/README.md
new file mode 100644
index 0000000..f0b8d62
--- /dev/null
+++ b/Functions/README.md
@@ -0,0 +1,21 @@
+# Cloud Functions for Firebase iOS SDK
+
+## To run unit tests
+
+Choose the FirebaseFunctions_Tests scheme and press Command-u.
+
+## To run integration tests
+
+Before running the integration tests, you'll need to start a backend emulator
+for them to talk to.
+
+1. Make sure you have `npm` installed.
+2. Run the backend startup script: `Backend/start.sh`
+ It will use `npm install` to automatically download the libraries it needs
+ to run the [Cloud Functions Local Emulator](https://cloud.google.com/functions/docs/emulator).
+ The first time you run it, it will ask for a projectId.
+ You can put anything you like. It will be ignored.
+3. Create the workspace in Functions/Example with `pod install`.
+4. `open FirebaseFunctions.xcworkspace`
+5. Choose the FirebaseFunctions_IntegrationTests scheme and press Command-u.
+6. When you are finished, you can press any key to stop the backend.
diff --git a/README.md b/README.md
index 2d44c9a..c54cdec 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
This repository contains a subset of the Firebase iOS SDK source. It currently
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
-FirebaseMessaging and FirebaseStorage.
+FirebaseFunctions, FirebaseMessaging and FirebaseStorage.
Firebase is an app development platform with tools to help you build, grow and
monetize your app. More information about Firebase can be found at
@@ -15,9 +15,10 @@ the Firebase iOS SDK. If you're interested in using the Firebase iOS SDK, start
## Context
This repo contains a fully functional development environment for FirebaseCore,
-FirebaseAuth, FirebaseDatabase, FirebaseFirestore, FirebaseMessaging, and
-FirebaseStorage. By following the usage instructions below, they can be
-developed and debugged with unit tests, integration tests, and reference samples.
+FirebaseAuth, FirebaseDatabase, FirebaseFirestore, FirebaseFunctions,
+FirebaseMessaging, and FirebaseStorage. By following the usage instructions
+below, they can be developed and debugged with unit tests, integration tests,
+and reference samples.
## Source pod integration
@@ -70,8 +71,9 @@ $ pod update
$ open Firebase.xcworkspace
```
-Firestore has a self contained Xcode project. See
-[Firestore/README.md](Firestore/README.md).
+Firestore and Functions have self contained Xcode projects. See
+[Firestore/README.md](Firestore/README.md) and
+[Functions/README.md](Functions/README.md).
### Running Unit Tests