adding pods method of package managing

This commit is contained in:
talksik
2021-12-13 12:34:20 -08:00
parent dad674aca7
commit 705203d7bd
5871 changed files with 1259393 additions and 3 deletions
@@ -0,0 +1,48 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
@protocol FIRAppCheckTokenResultInterop;
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(AppCheckTokenHandlerInterop)
typedef void (^FIRAppCheckTokenHandlerInterop)(id<FIRAppCheckTokenResultInterop> tokenResult);
@protocol FIRAppCheckInterop <NSObject>
/// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new
/// token and updates the cache.
- (void)getTokenForcingRefresh:(BOOL)forcingRefresh
completion:(FIRAppCheckTokenHandlerInterop)handler
NS_SWIFT_NAME(getToken(forcingRefresh:completion:));
/// A notification with the specified name is sent to the default notification center
/// (`NotificationCenter.default`) each time a Firebase app check token is refreshed.
/// The user info dictionary contains `-[self notificationTokenKey]` and
/// `-[self notificationAppNameKey]` keys.
- (NSString *)tokenDidChangeNotificationName;
/// `userInfo` key for the FAC token in a notification for `tokenDidChangeNotificationName`.
- (NSString *)notificationTokenKey;
/// `userInfo` key for the `FirebaseApp.name` in a notification for
/// `tokenDidChangeNotificationName`.
- (NSString *)notificationAppNameKey;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,32 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol FIRAppCheckTokenResultInterop <NSObject>
/// App Check token in the case of success or a dummy token in the case of a failure.
/// In general, the value of the token should always be set to the request header.
@property(nonatomic, readonly) NSString *token;
/// A token fetch error in the case of a failure or `nil` in the case of success.
@property(nonatomic, readonly, nullable) NSError *error;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,153 @@
/*
* Copyright 2017 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <FirebaseCore/FIRApp.h>
@class FIRComponentContainer;
@protocol FIRLibrary;
/**
* The internal interface to FIRApp. This is meant for first-party integrators, who need to receive
* FIRApp notifications, log info about the success or failure of their configuration, and access
* other internal functionality of FIRApp.
*
* TODO(b/28296561): Restructure this header.
*/
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, FIRConfigType) {
FIRConfigTypeCore = 1,
FIRConfigTypeSDK = 2,
};
extern NSString *const kFIRDefaultAppName;
extern NSString *const kFIRAppReadyToConfigureSDKNotification;
extern NSString *const kFIRAppDeleteNotification;
extern NSString *const kFIRAppIsDefaultAppKey;
extern NSString *const kFIRAppNameKey;
extern NSString *const kFIRGoogleAppIDKey;
extern NSString *const kFirebaseCoreErrorDomain;
/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */
extern NSString *const kFirebaseCoreDefaultsSuiteName;
/**
* The format string for the User Defaults key used for storing the data collection enabled flag.
* This includes formatting to append the Firebase App's name.
*/
extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat;
/**
* The plist key used for storing the data collection enabled flag.
*/
extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey;
/** @var FIRAuthStateDidChangeInternalNotification
@brief The name of the @c NSNotificationCenter notification which is posted when the auth state
changes (e.g. a new token has been produced, a user logs in or out). The object parameter of
the notification is a dictionary possibly containing the key:
@c FIRAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not
contain this key it indicates a sign-out event took place.
*/
extern NSString *const FIRAuthStateDidChangeInternalNotification;
/** @var FIRAuthStateDidChangeInternalNotificationTokenKey
@brief A key present in the dictionary object parameter of the
@c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
key will contain the new access token.
*/
extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey;
/** @var FIRAuthStateDidChangeInternalNotificationAppKey
@brief A key present in the dictionary object parameter of the
@c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
key will contain the FIRApp associated with the auth instance.
*/
extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey;
/** @var FIRAuthStateDidChangeInternalNotificationUIDKey
@brief A key present in the dictionary object parameter of the
@c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
key will contain the new user's UID (or nil if there is no longer a user signed in).
*/
extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
@interface FIRApp ()
/**
* A flag indicating if this is the default app (has the default app name).
*/
@property(nonatomic, readonly) BOOL isDefaultApp;
/*
* The container of interop SDKs for this app.
*/
@property(nonatomic) FIRComponentContainer *container;
/**
* Checks if the default app is configured without trying to configure it.
*/
+ (BOOL)isDefaultAppConfigured;
/**
* Registers a given third-party library with the given version number to be reported for
* analytics.
*
* @param name Name of the library.
* @param version Version of the library.
*/
+ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version;
/**
* Registers a given internal library to be reported for analytics.
*
* @param library Optional parameter for component registration.
* @param name Name of the library.
*/
+ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
withName:(nonnull NSString *)name;
/**
* Registers a given internal library with the given version number to be reported for
* analytics. This should only be used for non-Firebase libraries that have their own versioning
* scheme.
*
* @param library Optional parameter for component registration.
* @param name Name of the library.
* @param version Version of the library.
*/
+ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
withName:(nonnull NSString *)name
withVersion:(nonnull NSString *)version;
/**
* A concatenated string representing all the third-party libraries and version numbers.
*/
+ (NSString *)firebaseUserAgent;
/**
* Can be used by the unit tests in eack SDK to reset FIRApp. This method is thread unsafe.
*/
+ (void)resetApps;
/**
* Can be used by the unit tests in each SDK to set customized options.
*/
- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,91 @@
/*
* 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.
*/
#import <Foundation/Foundation.h>
@class FIRApp;
@class FIRComponentContainer;
NS_ASSUME_NONNULL_BEGIN
/// Provides a system to clean up cached instances returned from the component system.
NS_SWIFT_NAME(ComponentLifecycleMaintainer)
@protocol FIRComponentLifecycleMaintainer
/// The associated app will be deleted, clean up any resources as they are about to be deallocated.
- (void)appWillBeDeleted:(FIRApp *)app;
@end
typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container,
BOOL *isCacheable)
NS_SWIFT_NAME(ComponentCreationBlock);
@class FIRDependency;
/// Describes the timing of instantiation. Note: new components should default to lazy unless there
/// is a strong reason to be eager.
typedef NS_ENUM(NSInteger, FIRInstantiationTiming) {
FIRInstantiationTimingLazy,
FIRInstantiationTimingAlwaysEager,
FIRInstantiationTimingEagerInDefaultApp
} NS_SWIFT_NAME(InstantiationTiming);
/// A component that can be used from other Firebase SDKs.
NS_SWIFT_NAME(Component)
@interface FIRComponent : NSObject
/// The protocol describing functionality provided from the Component.
@property(nonatomic, strong, readonly) Protocol *protocol;
/// The timing of instantiation.
@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming;
/// An array of dependencies for the component.
@property(nonatomic, copy, readonly) NSArray<FIRDependency *> *dependencies;
/// A block to instantiate an instance of the component with the appropriate dependencies.
@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock;
// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format
// for the next two methods.
// clang-format off
/// Creates a component with no dependencies that will be lazily initialized.
+ (instancetype)componentWithProtocol:(Protocol *)protocol
creationBlock:(FIRComponentCreationBlock)creationBlock
NS_SWIFT_NAME(init(_:creationBlock:));
/// Creates a component to be registered with the component container.
///
/// @param protocol - The protocol describing functionality provided by the component.
/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's
/// a good reason to be instantiated earlier.
/// @param dependencies - Any dependencies the `implementingClass` has, optional or required.
/// @param creationBlock - A block to instantiate the component with a container, and if
/// @return A component that can be registered with the component container.
+ (instancetype)componentWithProtocol:(Protocol *)protocol
instantiationTiming:(FIRInstantiationTiming)instantiationTiming
dependencies:(NSArray<FIRDependency *> *)dependencies
creationBlock:(FIRComponentCreationBlock)creationBlock
NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:));
// clang-format on
/// Unavailable.
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,41 @@
/*
* 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// A type-safe macro to retrieve a component from a container. This should be used to retrieve
/// components instead of using the container directly.
#define FIR_COMPONENT(type, container) \
[FIRComponentType<id<type>> instanceForProtocol:@protocol(type) inContainer:container]
@class FIRApp;
/// A container that holds different components that are registered via the
/// `registerAsComponentRegistrant:` call. These classes should conform to `FIRComponentRegistrant`
/// in order to properly register components for Core.
NS_SWIFT_NAME(FirebaseComponentContainer)
@interface FIRComponentContainer : NSObject
/// A weak reference to the app that an instance of the container belongs to.
@property(nonatomic, weak, readonly) FIRApp *app;
/// Unavailable. Use the `container` property on `FIRApp`.
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/*
* 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.
*/
#import <Foundation/Foundation.h>
@class FIRComponentContainer;
NS_ASSUME_NONNULL_BEGIN
/// Do not use directly. A placeholder type in order to provide a macro that will warn users of
/// mis-matched protocols.
NS_SWIFT_NAME(ComponentType)
@interface FIRComponentType<__covariant T> : NSObject
/// Do not use directly. A factory method to retrieve an instance that provides a specific
/// functionality.
+ (T)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,35 @@
/*
* Copyright 2019 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 FIRDiagnosticsData;
@class FIROptions;
NS_ASSUME_NONNULL_BEGIN
/** Connects FIRCore with the CoreDiagnostics library. */
@interface FIRCoreDiagnosticsConnector : NSObject
/** Logs FirebaseCore related data.
*
* @param options The options object containing data to log.
*/
+ (void)logCoreTelemetryWithOptions:(FIROptions *)options;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
/*
* 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// A dependency on a specific protocol's functionality.
NS_SWIFT_NAME(Dependency)
@interface FIRDependency : NSObject
/// The protocol describing functionality being depended on.
@property(nonatomic, strong, readonly) Protocol *protocol;
/// A flag to specify if the dependency is required or not.
@property(nonatomic, readonly) BOOL isRequired;
/// Initializes a dependency that is required. Calls `initWithProtocol:isRequired` with `YES` for
/// the required parameter.
/// Creates a required dependency on the specified protocol's functionality.
+ (instancetype)dependencyWithProtocol:(Protocol *)protocol;
/// Creates a dependency on the specified protocol's functionality and specify if it's required for
/// the class's functionality.
+ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required;
/// Use `dependencyWithProtocol:isRequired:` instead.
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,39 @@
// Copyright 2019 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 FIRHeartbeatInfo : NSObject
// Enum representing the different heartbeat codes.
typedef NS_ENUM(NSInteger, FIRHeartbeatInfoCode) {
FIRHeartbeatInfoCodeNone = 0,
FIRHeartbeatInfoCodeSDK = 1,
FIRHeartbeatInfoCodeGlobal = 2,
FIRHeartbeatInfoCodeCombined = 3,
};
/**
* Get heartbeat code required for the sdk.
* @param heartbeatTag String representing the sdk heartbeat tag.
* @return Heartbeat code indicating whether or not an sdk/global heartbeat
* needs to be sent
*/
+ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef FIRLibrary_h
#define FIRLibrary_h
#import <Foundation/Foundation.h>
@class FIRApp;
@class FIRComponent;
NS_ASSUME_NONNULL_BEGIN
/// Provide an interface to register a library for userAgent logging and availability to others.
NS_SWIFT_NAME(Library)
@protocol FIRLibrary
/// Returns one or more FIRComponents that will be registered in
/// FIRApp and participate in dependency resolution and injection.
+ (NSArray<FIRComponent *> *)componentsToRegister;
@optional
/// Implement this method if the library needs notifications for lifecycle events. This method is
/// called when the developer calls `FirebaseApp.configure()`.
+ (void)configureWithApp:(FIRApp *)app;
@end
NS_ASSUME_NONNULL_END
#endif /* FIRLibrary_h */
@@ -0,0 +1,146 @@
/*
* 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 <FirebaseCore/FIRLoggerLevel.h>
NS_ASSUME_NONNULL_BEGIN
/**
* The Firebase services used in Firebase logger.
*/
typedef NSString *const FIRLoggerService;
extern FIRLoggerService kFIRLoggerAnalytics;
extern FIRLoggerService kFIRLoggerCrash;
extern FIRLoggerService kFIRLoggerCore;
extern FIRLoggerService kFIRLoggerRemoteConfig;
/**
* The key used to store the logger's error count.
*/
extern NSString *const kFIRLoggerErrorCountKey;
/**
* The key used to store the logger's warning count.
*/
extern NSString *const kFIRLoggerWarningCountKey;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Enables or disables Analytics debug mode.
* If set to YES, the logging level for Analytics will be set to FIRLoggerLevelDebug.
* Enabling the debug mode has no effect if the app is running from App Store.
* (required) analytics debug mode flag.
*/
void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode);
/**
* Changes the default logging level of FIRLoggerLevelNotice to a user-specified level.
* The default level cannot be set above FIRLoggerLevelNotice if the app is running from App Store.
* (required) log level (one of the FIRLoggerLevel enum values).
*/
void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel);
/**
* Checks if the specified logger level is loggable given the current settings.
* (required) log level (one of the FIRLoggerLevel enum values).
* (required) whether or not this function is called from the Analytics component.
*/
BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent);
/**
* Logs a message to the Xcode console and the device log. If running from AppStore, will
* not log any messages with a level higher than FIRLoggerLevelNotice to avoid log spamming.
* (required) log level (one of the FIRLoggerLevel enum values).
* (required) service name of type FIRLoggerService.
* (required) message code starting with "I-" which means iOS, followed by a capitalized
* three-character service identifier and a six digit integer message ID that is unique
* within the service.
* An example of the message code is @"I-COR000001".
* (required) message string which can be a format string.
* (optional) variable arguments list obtained from calling va_start, used when message is a format
* string.
*/
extern void FIRLogBasic(FIRLoggerLevel level,
FIRLoggerService service,
NSString *messageCode,
NSString *message,
// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable
// See: http://stackoverflow.com/q/29095469
#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX
va_list args_ptr
#else
va_list _Nullable args_ptr
#endif
);
/**
* The following functions accept the following parameters in order:
* (required) service name of type FIRLoggerService.
* (required) message code starting from "I-" which means iOS, followed by a capitalized
* three-character service identifier and a six digit integer message ID that is unique
* within the service.
* An example of the message code is @"I-COR000001".
* See go/firebase-log-proposal for details.
* (required) message string which can be a format string.
* (optional) the list of arguments to substitute into the format string.
* Example usage:
* FIRLogError(kFIRLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name);
*/
extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
@interface FIRLoggerWrapper : NSObject
/**
* Objective-C wrapper for FIRLogBasic to allow weak linking to FIRLogger
* (required) log level (one of the FIRLoggerLevel enum values).
* (required) service name of type FIRLoggerService.
* (required) message code starting with "I-" which means iOS, followed by a capitalized
* three-character service identifier and a six digit integer message ID that is unique
* within the service.
* An example of the message code is @"I-COR000001".
* (required) message string which can be a format string.
* (optional) variable arguments list obtained from calling va_start, used when message is a format
* string.
*/
+ (void)logWithLevel:(FIRLoggerLevel)level
withService:(FIRLoggerService)service
withCode:(NSString *)messageCode
withMessage:(NSString *)message
withArgs:(va_list)args;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,115 @@
/*
* 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 <FirebaseCore/FIROptions.h>
/**
* Keys for the strings in the plist file.
*/
extern NSString *const kFIRAPIKey;
extern NSString *const kFIRTrackingID;
extern NSString *const kFIRGoogleAppID;
extern NSString *const kFIRClientID;
extern NSString *const kFIRGCMSenderID;
extern NSString *const kFIRAndroidClientID;
extern NSString *const kFIRDatabaseURL;
extern NSString *const kFIRStorageBucket;
extern NSString *const kFIRBundleID;
extern NSString *const kFIRProjectID;
/**
* Keys for the plist file name
*/
extern NSString *const kServiceInfoFileName;
extern NSString *const kServiceInfoFileType;
/**
* This header file exposes the initialization of FIROptions to internal use.
*/
@interface FIROptions ()
/**
* resetDefaultOptions and initInternalWithOptionsDictionary: are exposed only for unit tests.
*/
+ (void)resetDefaultOptions;
/**
* Initializes the options with dictionary. The above strings are the keys of the dictionary.
* This is the designated initializer.
*/
- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary
NS_DESIGNATED_INITIALIZER;
/**
* defaultOptions and defaultOptionsDictionary are exposed in order to be used in FIRApp and
* other first party services.
*/
+ (FIROptions *)defaultOptions;
+ (NSDictionary *)defaultOptionsDictionary;
/**
* Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at
* runtime.
*/
@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet;
/**
* Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless
* explicitly disabled in GoogleService-Info.plist.
*/
@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled;
/**
* Whether or not Analytics Collection was completely disabled. If YES, then
* isAnalyticsCollectionEnabled will be NO.
*/
@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated;
/**
* The version ID of the client library, e.g. @"1100000".
*/
@property(nonatomic, readonly, copy) NSString *libraryVersionID;
/**
* The flag indicating whether this object was constructed with the values in the default plist
* file.
*/
@property(nonatomic) BOOL usingOptionsFromDefaultPlist;
/**
* Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in
* GoogleService-Info.plist.
*/
@property(nonatomic, readonly) BOOL isMeasurementEnabled;
/**
* Whether or not Analytics was enabled in the developer console.
*/
@property(nonatomic, readonly) BOOL isAnalyticsEnabled;
/**
* Whether or not SignIn was enabled in the developer console.
*/
@property(nonatomic, readonly) BOOL isSignInEnabled;
/**
* Whether or not editing is locked. This should occur after FIROptions has been set on a FIRApp.
*/
@property(nonatomic, getter=isEditingLocked) BOOL editingLocked;
@end
@@ -0,0 +1,28 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// An umbrella header, for any other libraries in this repo to access Firebase Public and Private
// headers. Any package manager complexity should be handled here.
#import <FirebaseCore/FirebaseCore.h>
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
#import "FirebaseCore/Sources/Private/FIRComponent.h"
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
#import "FirebaseCore/Sources/Private/FIRComponentType.h"
#import "FirebaseCore/Sources/Private/FIRDependency.h"
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
#import "FirebaseCore/Sources/Private/FIRLogger.h"
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
+373
View File
@@ -0,0 +1,373 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/FIRStorageComponent.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStoragePath.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h"
#import "FirebaseStorage/Sources/FIRStorageUtils.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h"
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
#import "Interop/Auth/Public/FIRAuthInterop.h"
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionFetcher.h>
#import <GTMSessionFetcher/GTMSessionFetcherLogging.h>
#endif
static NSMutableDictionary<
NSString * /* app name */,
NSMutableDictionary<NSString * /* bucket */, GTMSessionFetcherService *> *> *_fetcherServiceMap;
static GTMSessionFetcherRetryBlock _retryWhenOffline;
@interface FIRStorage () {
/// Stored Auth reference, if it exists. This needs to be stored for `copyWithZone:`.
id<FIRAuthInterop> _Nullable _auth;
id<FIRAppCheckInterop> _Nullable _appCheck;
BOOL _usesEmulator;
NSTimeInterval _maxUploadRetryTime;
NSTimeInterval _maxDownloadRetryTime;
NSTimeInterval _maxOperationRetryTime;
}
@end
@implementation FIRStorage
+ (void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_retryWhenOffline = ^(BOOL suggestedWillRetry, NSError *GTM_NULLABLE_TYPE error,
GTMSessionFetcherRetryResponse response) {
bool shouldRetry = suggestedWillRetry;
// GTMSessionFetcher does not consider being offline a retryable error, but we do, so we
// special-case it here.
if (!shouldRetry && error) {
shouldRetry = error.code == NSURLErrorNotConnectedToInternet;
}
response(shouldRetry);
};
_fetcherServiceMap = [[NSMutableDictionary alloc] init];
});
}
+ (GTMSessionFetcherService *)fetcherServiceForApp:(FIRApp *)app
bucket:(NSString *)bucket
auth:(nullable id<FIRAuthInterop>)auth
appCheck:(nullable id<FIRAppCheckInterop>)appCheck {
@synchronized(_fetcherServiceMap) {
NSMutableDictionary *bucketMap = _fetcherServiceMap[app.name];
if (!bucketMap) {
bucketMap = [[NSMutableDictionary alloc] init];
_fetcherServiceMap[app.name] = bucketMap;
}
GTMSessionFetcherService *fetcherService = bucketMap[bucket];
if (!fetcherService) {
fetcherService = [[GTMSessionFetcherService alloc] init];
[fetcherService setRetryEnabled:YES];
[fetcherService setRetryBlock:_retryWhenOffline];
[fetcherService setAllowLocalhostRequest:YES];
FIRStorageTokenAuthorizer *authorizer =
[[FIRStorageTokenAuthorizer alloc] initWithGoogleAppID:app.options.googleAppID
fetcherService:fetcherService
authProvider:auth
appCheck:appCheck];
[fetcherService setAuthorizer:authorizer];
bucketMap[bucket] = fetcherService;
}
return fetcherService;
}
}
+ (void)setGTMSessionFetcherLoggingEnabled:(BOOL)isLoggingEnabled {
[GTMSessionFetcher setLoggingEnabled:isLoggingEnabled];
}
+ (instancetype)storage {
return [self storageForApp:[FIRApp defaultApp]];
}
+ (instancetype)storageForApp:(FIRApp *)app {
if (app.options.storageBucket) {
NSString *url = [app.options.storageBucket isEqualToString:@""]
? @""
: [@"gs://" stringByAppendingString:app.options.storageBucket];
return [self storageForApp:app URL:url];
} else {
NSString *const kAppNotConfiguredMessage =
@"No default Storage bucket found. Did you configure Firebase Storage properly?";
[NSException raise:NSInvalidArgumentException format:kAppNotConfiguredMessage];
return nil;
}
}
+ (instancetype)storageWithURL:(NSString *)url {
return [self storageForApp:[FIRApp defaultApp] URL:url];
}
+ (instancetype)storageForApp:(FIRApp *)app URL:(NSString *)url {
NSString *bucket;
if ([url isEqualToString:@""]) {
bucket = @"";
} else {
FIRStoragePath *path;
@try {
path = [FIRStoragePath pathFromGSURI:url];
} @catch (NSException *e) {
[NSException raise:NSInternalInconsistencyException
format:@"URI must be in the form of gs://<bucket>/"];
}
if (path.object != nil && ![path.object isEqualToString:@""]) {
[NSException raise:NSInternalInconsistencyException
format:@"Storage bucket cannot be initialized with a path"];
}
bucket = path.bucket;
}
// Retrieve the instance provider from the app's container to inject dependencies as needed.
id<FIRStorageMultiBucketProvider> provider =
FIR_COMPONENT(FIRStorageMultiBucketProvider, app.container);
return [provider storageForBucket:bucket];
}
- (instancetype)initWithApp:(FIRApp *)app
bucket:(NSString *)bucket
auth:(nullable id<FIRAuthInterop>)auth
appCheck:(nullable id<FIRAppCheckInterop>)appCheck {
self = [super init];
if (self) {
_app = app;
_auth = auth;
_appCheck = appCheck;
_storageBucket = bucket;
_host = kFIRStorageHost;
_scheme = kFIRStorageScheme;
_port = @(kFIRStoragePort);
_fetcherServiceForApp = nil; // Configured in `ensureConfigured()`
// Must be a serial queue.
_dispatchQueue = dispatch_queue_create("com.google.firebase.storage", DISPATCH_QUEUE_SERIAL);
_maxDownloadRetryTime = 600.0;
_maxDownloadRetryInterval =
[FIRStorageUtils computeRetryIntervalFromRetryTime:_maxDownloadRetryTime];
_maxOperationRetryTime = 120.0;
_maxOperationRetryInterval =
[FIRStorageUtils computeRetryIntervalFromRetryTime:_maxOperationRetryTime];
_maxUploadRetryTime = 600.0;
_maxUploadRetryInterval =
[FIRStorageUtils computeRetryIntervalFromRetryTime:_maxUploadRetryTime];
}
return self;
}
- (instancetype)init {
NSAssert(false, @"Storage cannot be directly instantiated, use "
"Storage.storage() or Storage.storage(app:) instead");
return nil;
}
#pragma mark - NSObject overrides
- (instancetype)copyWithZone:(NSZone *)zone {
FIRStorage *storage = [[[self class] allocWithZone:zone] initWithApp:_app
bucket:_storageBucket
auth:_auth
appCheck:_appCheck];
storage.callbackQueue = self.callbackQueue;
return storage;
}
// Two FIRStorage objects are equal if they use the same app
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FIRStorage class]]) {
return NO;
}
BOOL isEqualObject = [self isEqualToFIRStorage:(FIRStorage *)object];
return isEqualObject;
}
- (BOOL)isEqualToFIRStorage:(FIRStorage *)storage {
BOOL isEqual =
[_app isEqual:storage.app] && [_storageBucket isEqualToString:storage.storageBucket];
return isEqual;
}
- (NSUInteger)hash {
NSUInteger hash = [_app hash] ^ [self.callbackQueue hash];
return hash;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, _app];
}
#pragma mark - Retry time intervals
- (void)setMaxUploadRetryTime:(NSTimeInterval)maxUploadRetryTime {
@synchronized(self) {
_maxUploadRetryTime = maxUploadRetryTime;
_maxUploadRetryInterval =
[FIRStorageUtils computeRetryIntervalFromRetryTime:maxUploadRetryTime];
}
}
- (NSTimeInterval)maxDownloadRetryTime {
@synchronized(self) {
return _maxDownloadRetryTime;
}
}
- (void)setMaxDownloadRetryTime:(NSTimeInterval)maxDownloadRetryTime {
@synchronized(self) {
_maxDownloadRetryTime = maxDownloadRetryTime;
_maxDownloadRetryInterval =
[FIRStorageUtils computeRetryIntervalFromRetryTime:maxDownloadRetryTime];
}
}
- (NSTimeInterval)maxUploadRetryTime {
@synchronized(self) {
return _maxUploadRetryTime;
}
}
- (void)setMaxOperationRetryTime:(NSTimeInterval)maxOperationRetryTime {
@synchronized(self) {
_maxOperationRetryTime = maxOperationRetryTime;
_maxOperationRetryInterval =
[FIRStorageUtils computeRetryIntervalFromRetryTime:maxOperationRetryTime];
}
}
- (NSTimeInterval)maxOperationRetryTime {
@synchronized(self) {
return _maxOperationRetryTime;
}
}
#pragma mark - Public methods
- (FIRStorageReference *)reference {
[self ensureConfigured];
FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:_storageBucket object:nil];
return [[FIRStorageReference alloc] initWithStorage:self path:path];
}
- (FIRStorageReference *)referenceForURL:(NSString *)string {
[self ensureConfigured];
FIRStoragePath *path = [FIRStoragePath pathFromString:string];
// If no default bucket exists (empty string), accept anything.
if ([_storageBucket isEqual:@""]) {
FIRStorageReference *reference = [[FIRStorageReference alloc] initWithStorage:self path:path];
return reference;
}
// If there exists a default bucket, throw if provided a different bucket.
if (![path.bucket isEqual:_storageBucket]) {
NSString *const kInvalidBucketFormat =
@"Provided bucket: %@ does not match the Storage bucket of the current instance: %@";
[NSException raise:NSInvalidArgumentException
format:kInvalidBucketFormat, path.bucket, _storageBucket];
}
FIRStorageReference *reference = [[FIRStorageReference alloc] initWithStorage:self path:path];
return reference;
}
- (FIRStorageReference *)referenceWithPath:(NSString *)string {
FIRStorageReference *reference = [[self reference] child:string];
return reference;
}
- (dispatch_queue_t)callbackQueue {
[self ensureConfigured];
return _fetcherServiceForApp.callbackQueue;
}
- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue {
[self ensureConfigured];
_fetcherServiceForApp.callbackQueue = callbackQueue;
}
- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port {
if (host.length == 0) {
[NSException raise:NSInvalidArgumentException format:@"Cannot connect to nil or empty host."];
}
if (port < 0) {
[NSException raise:NSInvalidArgumentException
format:@"Port must be greater than or equal to zero."];
}
if (_fetcherServiceForApp != nil) {
[NSException raise:NSInternalInconsistencyException
format:@"Cannot connect to emulator after Storage SDK initialization. "
@"Call useEmulator(host:port:) before creating a Storage "
@"reference or trying to load data."];
}
_usesEmulator = YES;
_scheme = @"http";
_host = host;
_port = @(port);
}
#pragma mark - Background tasks
+ (void)enableBackgroundTasks:(BOOL)isEnabled {
[NSException raise:NSGenericException format:@"enableBackgroundTasks not implemented"];
}
- (NSArray<FIRStorageUploadTask *> *)uploadTasks {
[NSException raise:NSGenericException format:@"getUploadTasks not implemented"];
return nil;
}
- (NSArray<FIRStorageDownloadTask *> *)downloadTasks {
[NSException raise:NSGenericException format:@"getDownloadTasks not implemented"];
return nil;
}
- (void)ensureConfigured {
if (!_fetcherServiceForApp) {
_fetcherServiceForApp = [FIRStorage fetcherServiceForApp:_app
bucket:_storageBucket
auth:_auth
appCheck:_appCheck];
if (_usesEmulator) {
_fetcherServiceForApp.allowLocalhostRequest = YES;
_fetcherServiceForApp.allowedInsecureSchemes = @[ @"http" ];
}
}
}
@end
@@ -0,0 +1,45 @@
// 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.
#import <Foundation/Foundation.h>
@class FIRApp;
@class FIRStorage;
NS_ASSUME_NONNULL_BEGIN
/// This protocol is used in the interop registration process to register an instance provider for
/// individual FIRApps.
@protocol FIRStorageMultiBucketProvider
/// Default method for creating a Storage instance.
- (FIRStorage *)storageForBucket:(NSString *)bucket;
@end
/// A concrete implementation for FIRStorageMultiBucketProvider to create Storage instances.
@interface FIRStorageComponent : NSObject <FIRStorageMultiBucketProvider>
/// The FIRApp that instances will be set up with.
@property(nonatomic, weak, readonly) FIRApp *app;
/// Default method for creating a Storage instance.
- (FIRStorage *)storageForBucket:(NSString *)bucket;
/// Unavailable, use `storageForApp:storageURL:` instead.
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,102 @@
// 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.
#import "FirebaseStorage/Sources/FIRStorageComponent.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h"
#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h"
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
#import "Interop/Auth/Public/FIRAuthInterop.h"
NS_ASSUME_NONNULL_BEGIN
/** A NSMutableDictionary of FirebaseApp name and bucket names to FIRStorage instance. */
typedef NSMutableDictionary<NSString *, FIRStorage *> FIRStorageDictionary;
@interface FIRStorage ()
// Surface the internal initializer to create instances of FIRStorage.
- (instancetype)initWithApp:(FIRApp *)app
bucket:(NSString *)bucket
auth:(nullable id<FIRAuthInterop>)auth
appCheck:(nullable id<FIRAppCheckInterop>)appCheck;
@end
@interface FIRStorageComponent () <FIRLibrary>
@property(nonatomic) FIRStorageDictionary *instances;
/// Internal initializer.
- (instancetype)initWithApp:(FIRApp *)app;
@end
@implementation FIRStorageComponent
#pragma mark - Initialization
- (instancetype)initWithApp:(FIRApp *)app {
self = [super init];
if (self) {
_app = app;
_instances = [NSMutableDictionary dictionary];
}
return self;
}
#pragma mark - Lifecycle
+ (void)load {
[FIRApp registerInternalLibrary:(Class<FIRLibrary>)self withName:@"fire-str"];
}
#pragma mark - FIRComponentRegistrant
+ (nonnull NSArray<FIRComponent *> *)componentsToRegister {
FIRDependency *authDep = [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop)
isRequired:NO];
FIRComponentCreationBlock creationBlock =
^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {
*isCacheable = YES;
return [[FIRStorageComponent alloc] initWithApp:container.app];
};
FIRComponent *storageProvider =
[FIRComponent componentWithProtocol:@protocol(FIRStorageMultiBucketProvider)
instantiationTiming:FIRInstantiationTimingLazy
dependencies:@[ authDep ]
creationBlock:creationBlock];
return @[ storageProvider ];
}
#pragma mark - FIRStorageInstanceProvider Conformance
- (FIRStorage *)storageForBucket:(NSString *)bucket {
FIRStorageDictionary *instances = [self instances];
@synchronized(instances) {
FIRStorage *instance = instances[bucket];
if (!instance) {
// Create an instance of FIRStorage and return it.
id<FIRAuthInterop> auth = FIR_COMPONENT(FIRAuthInterop, self.app.container);
id<FIRAppCheckInterop> appCheck = FIR_COMPONENT(FIRAppCheckInterop, self.app.container);
instance = [[FIRStorage alloc] initWithApp:self.app
bucket:bucket
auth:auth
appCheck:appCheck];
instances[bucket] = instance;
}
return instance;
}
}
@end
NS_ASSUME_NONNULL_END
@@ -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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
NSString *const kGCSScheme = @"https";
NSString *const kGCSHost = @"www.googleapis.com";
NSString *const kGCSUploadPath = @"upload";
NSString *const kGCSStorageVersionPath = @"storage/v1";
NSString *const kGCSBucketPathFormat = @"b/%@";
NSString *const kGCSObjectPathFormat = @"o/%@";
NSString *const kFIRStorageScheme = @"https";
NSString *const kFIRStorageHost = @"firebasestorage.googleapis.com";
NSInteger const kFIRStoragePort = 443;
NSString *const kFIRStorageVersionPath = @"v0";
NSString *const kFIRStorageBucketPathFormat = @"b/%@";
NSString *const kFIRStorageObjectPathFormat = @"o/%@";
NSString *const kFIRStorageFullPathFormat = @"/v0/b/%@/o/%@";
NSString *const kFIRStorageAuthTokenFormat = @"Firebase %@";
NSString *const kFIRStorageDefaultBucketFormat = @"gs://%@";
NSString *const kFIRStorageResponseErrorDomain = @"ResponseErrorDomain";
NSString *const kFIRStorageResponseErrorCode = @"ResponseErrorCode";
NSString *const kFIRStorageResponseBody = @"ResponseBody";
NSString *const FIRStorageErrorDomain = @"FIRStorageErrorDomain";
NSString *const kFIRStorageInvalidDataFormat = @"Invalid data returned from the server: %@";
NSString *const kFIRStorageInvalidObserverStatus =
@"Invalid observer status requested, use one "
@"of: FIRStorageTaskStatusPause, Resume, Progress, "
@"Complete, or Failure";
/**
* String constants mapping GCS Object#list results to ListResult fields.
*/
NSString *const kFIRStorageListPrefixes = @"prefixes";
NSString *const kFIRStorageListItems = @"items";
NSString *const kFIRStorageListItemName = @"name";
NSString *const kFIRStorageListPageToken = @"nextPageToken";
/**
* String constants mapping GCS Object#resource mappings to metadata fields.
*/
NSString *const kFIRStorageMetadataBucket = @"bucket";
NSString *const kFIRStorageMetadataCacheControl = @"cacheControl";
NSString *const kFIRStorageMetadataContentDisposition = @"contentDisposition";
NSString *const kFIRStorageMetadataContentEncoding = @"contentEncoding";
NSString *const kFIRStorageMetadataContentLanguage = @"contentLanguage";
NSString *const kFIRStorageMetadataContentType = @"contentType";
NSString *const kFIRStorageMetadataCustomMetadata = @"metadata";
NSString *const kFIRStorageMetadataSize = @"size";
NSString *const kFIRStorageMetadataGeneration = @"generation";
NSString *const kFIRStorageMetadataMetageneration = @"metageneration";
NSString *const kFIRStorageMetadataTimeCreated = @"timeCreated";
NSString *const kFIRStorageMetadataUpdated = @"updated";
NSString *const kFIRStorageMetadataName = @"name";
NSString *const kFIRStorageMetadataDownloadTokens = @"downloadTokens";
NSString *const kFIRStorageMetadataMd5Hash = @"md5Hash";
// TODO: add notification support
NSString *const kFIRStorageTaskStatusResumeNotification =
@"kFIRStorageTaskStatusResumeNotification";
NSString *const kFIRStorageTaskStatusPauseNotification = @"kFIRStorageTaskStatusResumeNotification";
NSString *const kFIRStorageTaskStatusProgressNotification =
@"kFIRStorageTaskStatusResumeNotification";
NSString *const kFIRStorageTaskStatusCompleteNotification =
@"kFIRStorageTaskStatusResumeNotification";
NSString *const kFIRStorageTaskStatusFailureNotification =
@"kFIRStorageTaskStatusResumeNotification";
NSString *const kFIRStorageBundleIdentifier = @"com.google.firebase.storage";
@@ -0,0 +1,151 @@
/*
* 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 FIRStorageMetadata;
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSString *const kGCSScheme;
FOUNDATION_EXPORT NSString *const kGCSHost;
FOUNDATION_EXPORT NSString *const kGCSUploadPath;
FOUNDATION_EXPORT NSString *const kGCSStorageVersionPath;
FOUNDATION_EXPORT NSString *const kGCSBucketPathFormat;
FOUNDATION_EXPORT NSString *const kGCSObjectPathFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageScheme;
FOUNDATION_EXPORT NSString *const kFIRStorageHost;
FOUNDATION_EXPORT NSInteger const kFIRStoragePort;
FOUNDATION_EXPORT NSString *const kFIRStorageVersionPath;
FOUNDATION_EXPORT NSString *const kFIRStorageBucketPathFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageObjectPathFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageFullPathFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageAuthTokenFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageDefaultBucketFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageResponseErrorDomain;
FOUNDATION_EXPORT NSString *const kFIRStorageResponseErrorCode;
FOUNDATION_EXPORT NSString *const kFIRStorageResponseBody;
FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusResumeNotification;
FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusPauseNotification;
FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusProgressNotification;
FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusCompleteNotification;
FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusFailureNotification;
FOUNDATION_EXPORT NSString *const kFIRStorageListPrefixes;
FOUNDATION_EXPORT NSString *const kFIRStorageListItems;
FOUNDATION_EXPORT NSString *const kFIRStorageListItemName;
FOUNDATION_EXPORT NSString *const kFIRStorageListPageToken;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataBucket;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataCacheControl;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentDisposition;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentEncoding;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentLanguage;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentType;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataCustomMetadata;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataSize;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataGeneration;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataMetageneration;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataTimeCreated;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataUpdated;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataName;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataDownloadTokens;
FOUNDATION_EXPORT NSString *const kFIRStorageMetadataMd5Hash;
FOUNDATION_EXPORT NSString *const kFIRStorageInvalidDataFormat;
FOUNDATION_EXPORT NSString *const kFIRStorageInvalidObserverStatus;
FOUNDATION_EXPORT NSString *const kFIRStorageBundleIdentifier;
/**
* Enum representing the internal state of an upload or download task.
*/
typedef NS_ENUM(NSInteger, FIRStorageTaskState) {
/**
* Unknown task state
*/
FIRStorageTaskStateUnknown,
/**
* Task is being queued is ready to run
*/
FIRStorageTaskStateQueueing,
/**
* Task is resuming from a paused state
*/
FIRStorageTaskStateResuming,
/**
* Task is currently running
*/
FIRStorageTaskStateRunning,
/**
* Task reporting a progress event
*/
FIRStorageTaskStateProgress,
/**
* Task is pausing
*/
FIRStorageTaskStatePausing,
/**
* Task is completing successfully
*/
FIRStorageTaskStateCompleting,
/**
* Task is failing unrecoverably
*/
FIRStorageTaskStateFailing,
/**
* Task paused successfully
*/
FIRStorageTaskStatePaused,
/**
* Task cancelled successfully
*/
FIRStorageTaskStateCancelled,
/**
* Task completed successfully
*/
FIRStorageTaskStateSuccess,
/**
* Task failed unrecoverably
*/
FIRStorageTaskStateFailed
};
/**
* Represents the various types of metadata: Files or Folders.
*/
typedef NS_ENUM(NSUInteger, FIRStorageMetadataType) {
FIRStorageMetadataTypeUnknown,
FIRStorageMetadataTypeFile,
FIRStorageMetadataTypeFolder,
};
NS_ASSUME_NONNULL_END
@@ -0,0 +1,35 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h"
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
/**
* Task which provides the ability to delete an object in Firebase Storage.
*/
@interface FIRStorageDeleteTask : FIRStorageTask <FIRStorageTaskManagement>
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
completion:(FIRStorageVoidError)completion;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,83 @@
// 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 "FirebaseStorage/Sources/FIRStorageDeleteTask.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
@implementation FIRStorageDeleteTask {
@private
FIRStorageVoidError _completion;
}
@synthesize fetcher = _fetcher;
@synthesize fetcherCompletion = _fetcherCompletion;
- (void)dealloc {
[_fetcher stopFetching];
}
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
completion:(FIRStorageVoidError)completion {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_completion = [completion copy];
}
return self;
}
- (void)enqueue {
__weak FIRStorageDeleteTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageDeleteTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
request.HTTPMethod = @"DELETE";
request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime;
FIRStorageVoidError callback = strongSelf->_completion;
strongSelf->_completion = nil;
GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
strongSelf->_fetcher = fetcher;
fetcher.comment = @"DeleteTask";
strongSelf->_fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) {
if (!self.error) {
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
}
if (callback) {
callback(self.error);
}
self->_fetcherCompletion = nil;
};
[fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) {
FIRStorageDeleteTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
}
@end
@@ -0,0 +1,199 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
@implementation FIRStorageDownloadTask
@synthesize progress = _progress;
@synthesize fetcher = _fetcher;
@synthesize fetcherCompletion = _fetcherCompletion;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
file:(nullable NSURL *)fileURL {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_fileURL = [fileURL copy];
_progress = [NSProgress progressWithTotalUnitCount:0];
}
return self;
}
- (void)dealloc {
[_fetcher stopFetching];
}
- (void)enqueue {
[self enqueueWithData:nil];
}
- (void)enqueueWithData:(nullable NSData *)resumeData {
__weak FIRStorageDownloadTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageDownloadTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
strongSelf.state = FIRStorageTaskStateQueueing;
NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
request.HTTPMethod = @"GET";
request.timeoutInterval = strongSelf.reference.storage.maxDownloadRetryTime;
NSURLComponents *components = [NSURLComponents componentsWithURL:request.URL
resolvingAgainstBaseURL:NO];
[components setQuery:@"alt=media"];
request.URL = components.URL;
GTMSessionFetcher *fetcher;
if (resumeData) {
fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData];
fetcher.comment = @"Resuming DownloadTask";
} else {
fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
fetcher.comment = @"Starting DownloadTask";
}
[fetcher setResumeDataBlock:^(NSData *data) {
FIRStorageDownloadTask *strong = weakSelf;
if (strong && data) {
strong->_downloadData = data;
}
}];
fetcher.maxRetryInterval = strongSelf.reference.storage.maxDownloadRetryInterval;
if (strongSelf->_fileURL) {
// Handle file downloads
[fetcher setDestinationFileURL:strongSelf->_fileURL];
[fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten,
int64_t totalBytesExpectedToWrite) {
weakSelf.state = FIRStorageTaskStateProgress;
weakSelf.progress.completedUnitCount = totalBytesWritten;
weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite;
FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
weakSelf.state = FIRStorageTaskStateRunning;
}];
} else {
// Handle data downloads
[fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) {
weakSelf.state = FIRStorageTaskStateProgress;
weakSelf.progress.completedUnitCount = totalBytesWritten;
int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength];
weakSelf.progress.totalUnitCount = totalLength;
FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
weakSelf.state = FIRStorageTaskStateRunning;
}];
}
strongSelf->_fetcher = fetcher;
strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
// Fire last progress updates
[self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot];
// Handle potential issues with download
if (error) {
self.state = FIRStorageTaskStateFailed;
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
[self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot];
[self removeAllObservers];
self->_fetcherCompletion = nil;
return;
}
// Download completed successfully, fire completion callbacks
self.state = FIRStorageTaskStateSuccess;
if (data) {
self->_downloadData = data;
}
[self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot];
[self removeAllObservers];
self->_fetcherCompletion = nil;
};
strongSelf.state = FIRStorageTaskStateRunning;
[strongSelf.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
FIRStorageDownloadTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
}
#pragma mark - Download Management
- (void)cancel {
NSError *error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled];
[self cancelWithError:error];
}
- (void)cancelWithError:(NSError *)error {
__weak FIRStorageDownloadTask *weakSelf = self;
[self dispatchAsync:^() {
weakSelf.state = FIRStorageTaskStateCancelled;
[weakSelf.fetcher stopFetching];
weakSelf.error = error;
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot];
}];
}
- (void)pause {
__weak FIRStorageDownloadTask *weakSelf = self;
[self dispatchAsync:^() {
__strong FIRStorageDownloadTask *strongSelf = weakSelf;
if (!strongSelf || strongSelf.state == FIRStorageTaskStatePaused ||
strongSelf.state == FIRStorageTaskStatePausing) {
return;
}
strongSelf.state = FIRStorageTaskStatePausing;
// Use the resume callback to confirm pause status since it always runs after the last
// NSURLSession update.
[strongSelf.fetcher setResumeDataBlock:^(NSData *data) {
// Silence compiler warning about retain cycles
__strong __typeof(self) strong = weakSelf;
strong->_downloadData = data;
strong.state = FIRStorageTaskStatePaused;
FIRStorageTaskSnapshot *snapshot = strong.snapshot;
[strong fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot];
}];
[strongSelf.fetcher stopFetching];
}];
}
- (void)resume {
__weak FIRStorageDownloadTask *weakSelf = self;
[self dispatchAsync:^() {
weakSelf.state = FIRStorageTaskStateResuming;
FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot];
weakSelf.state = FIRStorageTaskStateRunning;
[weakSelf enqueueWithData:weakSelf.downloadData];
}];
}
@end
@@ -0,0 +1,59 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h"
@class FIRStorageReference;
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageDownloadTask ()
/**
* Bytes which have been downloaded so far.
*/
@property(readonly, nonatomic) NSData *downloadData;
/**
* The file on disk to write to.
*/
@property(copy, nonatomic) NSURL *fileURL;
/**
* Initializes a download task with a base FIRStorageReference and GTMSessionFetcherService.
* @param reference The base FIRStorageReference which fetchers use for configuration.
* @param service The GTMSessionFetcherService which will create fetchers.
* @param queue The shared queue to use for all Storage operations.
* @param fileURL The system URL to download to. If nil, download in memory as bytes.
* @return Returns an instance of FIRStorageDownloadTask
*/
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
file:(nullable NSURL *)fileURL;
/**
* Cancels the download task and passes an appropriate error to the developer.
* @param error NSError to propegate to the developer.
*/
- (void)cancelWithError:(NSError *)error;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,70 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h"
NS_ASSUME_NONNULL_BEGIN
@class FIRStorageReference;
/**
* Adds wrappers for common Firebase Storage errors (including creating errors from GCS errors).
* For more information on unwrapping GCS errors, see the GCS errors docs:
* https://cloud.google.com/storage/docs/json_api/v1/status-codes
* This is never publicly exposed to end developers (as they will simply see an NSError).
*/
@interface FIRStorageErrors : NSObject
/**
* Creates a Firebase Storage error from a specific FIRStorageErrorCode.
*/
+ (NSError *)errorWithCode:(FIRStorageErrorCode)code;
/**
* Creates a Firebase Storage error from a specific FIRStorageErrorCode while adding
* custom info from an optionally provided info dictionary.
*/
+ (NSError *)errorWithCode:(FIRStorageErrorCode)code
infoDictionary:(nullable NSDictionary *)dictionary;
/**
* Creates a Firebase Storage error from a specific GCS error and FIRStorageReference.
* @param error Server error to wrap and return as a Firebase Storage error.
* @param reference FIRStorageReference which provides context about the request being made.
* @return Returns a Firebase Storage error, or nil if no error is provided.
*/
+ (nullable NSError *)errorWithServerError:(nullable NSError *)error
reference:(nullable FIRStorageReference *)reference;
/**
* Creates a Firebase Storage error from an invalid request.
*
* @param request The NSData representation of the invalid user request.
* @return Returns the corresponding Firebase Storage error.
*/
+ (NSError *)errorWithInvalidRequest:(NSData *)request;
/**
* Creates a Firebase Storage error with a custom error message.
*
* @param errorMessage A custom error message.
* @return Returns the corresponding Firebase Storage error.
*/
+ (NSError *)errorWithCustomMessage:(NSString *)errorMessage;
@end
NS_ASSUME_NONNULL_END
@@ -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 "FirebaseStorage/Sources/FIRStorageErrors.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
@implementation FIRStorageErrors
+ (NSError *)errorWithCode:(FIRStorageErrorCode)code {
return [FIRStorageErrors errorWithCode:code infoDictionary:nil];
}
+ (NSError *)errorWithCode:(FIRStorageErrorCode)code
infoDictionary:(nullable NSDictionary *)dictionary {
NSMutableDictionary *errorDictionary;
if (dictionary) {
errorDictionary = [dictionary mutableCopy];
} else {
errorDictionary = [[NSMutableDictionary alloc] init];
}
NSString *errorMessage;
switch (code) {
case FIRStorageErrorCodeObjectNotFound:
errorMessage =
[NSString stringWithFormat:@"Object %@ does not exist.", errorDictionary[@"object"]];
break;
case FIRStorageErrorCodeBucketNotFound:
errorMessage =
[NSString stringWithFormat:@"Bucket %@ does not exist.", errorDictionary[@"bucket"]];
break;
case FIRStorageErrorCodeProjectNotFound:
errorMessage =
[NSString stringWithFormat:@"Project %@ does not exist.", errorDictionary[@"project"]];
break;
case FIRStorageErrorCodeQuotaExceeded: {
NSString *const kQuotaExceededFormat =
@"Quota for bucket %@ exceeded, please view quota on firebase.google.com.";
errorMessage = [NSString stringWithFormat:kQuotaExceededFormat, errorDictionary[@"bucket"]];
break;
}
case FIRStorageErrorCodeDownloadSizeExceeded: {
int64_t total = [errorDictionary[@"totalSize"] longLongValue];
int64_t size = [errorDictionary[@"maxAllowedSize"] longLongValue];
NSString *totalString = total ? @(total).stringValue : @"unknown";
NSString *sizeString = total ? @(size).stringValue : @"unknown";
NSString *const kSizeExceededErrorFormat =
@"Attempted to download object with size of %@ bytes, "
@"which exceeds the maximum size of %@ bytes. "
@"Consider raising the maximum download size, or using "
@"[FIRStorageReference writeToFile:]";
errorMessage = [NSString stringWithFormat:kSizeExceededErrorFormat, totalString, sizeString];
break;
}
case FIRStorageErrorCodeUnauthenticated:
errorMessage = @"User is not authenticated, please authenticate using Firebase "
@"Authentication and try again.";
break;
case FIRStorageErrorCodeUnauthorized: {
NSString *bucket = errorDictionary[@"bucket"];
NSString *object = errorDictionary[@"object"];
NSString *const kUnauthorizedFormat = @"User does not have permission to access gs://%@/%@.";
errorMessage = [NSString stringWithFormat:kUnauthorizedFormat, bucket, object];
break;
}
case FIRStorageErrorCodeRetryLimitExceeded:
errorMessage = @"Max retry time for operation exceeded, please try again.";
break;
case FIRStorageErrorCodeNonMatchingChecksum: {
// TODO: replace with actual checksum strings when we choose to implement.
NSString *const kChecksumFailedErrorFormat =
@"Uploaded/downloaded object %@ has checksum: %@ "
@"which does not match server checksum: %@. Please retry the upload/download.";
errorMessage = [NSString stringWithFormat:kChecksumFailedErrorFormat, @"object",
@"client checksum", @"server checksum"];
break;
}
case FIRStorageErrorCodeCancelled:
errorMessage = @"User cancelled the upload/download.";
break;
case FIRStorageErrorCodeUnknown:
/* Fall through to default case for unknown errors */
default:
errorMessage = @"An unknown error occurred, please check the server response.";
break;
}
errorDictionary[NSLocalizedDescriptionKey] = errorMessage;
NSError *err = [NSError errorWithDomain:FIRStorageErrorDomain code:code userInfo:errorDictionary];
return err;
}
+ (nullable NSError *)errorWithServerError:(nullable NSError *)error
reference:(nullable FIRStorageReference *)reference {
if (error == nil) {
return nil;
}
FIRStorageErrorCode errorCode;
switch (error.code) {
case 400:
errorCode = FIRStorageErrorCodeUnknown;
break;
case 401:
errorCode = FIRStorageErrorCodeUnauthenticated;
break;
case 402:
errorCode = FIRStorageErrorCodeQuotaExceeded;
break;
case 403:
errorCode = FIRStorageErrorCodeUnauthorized;
break;
case 404:
errorCode = FIRStorageErrorCodeObjectNotFound;
break;
default:
errorCode = FIRStorageErrorCodeUnknown;
break;
}
NSMutableDictionary *errorDictionary =
[[[NSDictionary alloc] initWithDictionary:error.userInfo] mutableCopy];
errorDictionary[kFIRStorageResponseErrorDomain] = error.domain;
errorDictionary[kFIRStorageResponseErrorCode] = @(error.code);
// Turn raw response into a string
NSData *responseData = errorDictionary[@"data"];
if (responseData) {
NSString *errorString = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding];
errorDictionary[kFIRStorageResponseBody] = errorString ?: @"No Response from Server.";
}
errorDictionary[@"bucket"] = reference.path.bucket;
errorDictionary[@"object"] = reference.path.object;
NSError *clientError = [FIRStorageErrors errorWithCode:errorCode infoDictionary:errorDictionary];
return clientError;
}
+ (NSError *)errorWithInvalidRequest:(NSData *)request {
NSString *requestString = [[NSString alloc] initWithData:request encoding:NSUTF8StringEncoding];
NSString *invalidDataString =
[NSString stringWithFormat:kFIRStorageInvalidDataFormat, requestString];
NSDictionary *dict;
if (invalidDataString.length > 0) {
dict = @{NSLocalizedFailureReasonErrorKey : invalidDataString};
}
return [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict];
}
+ (NSError *)errorWithCustomMessage:(NSString *)errorMessage {
return [NSError errorWithDomain:FIRStorageErrorDomain
code:FIRStorageErrorCodeUnknown
userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
}
@end
@@ -0,0 +1,35 @@
/*
* 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.
*/
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h"
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
/**
* Task which provides the ability to get a download URL for an object in Firebase Storage.
*/
@interface FIRStorageGetDownloadURLTask : FIRStorageTask <FIRStorageTaskManagement>
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
completion:(FIRStorageVoidURLError)completion;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,126 @@
// 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.
#import "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
@implementation FIRStorageGetDownloadURLTask {
@private
FIRStorageVoidURLError _completion;
}
@synthesize fetcher = _fetcher;
@synthesize fetcherCompletion = _fetcherCompletion;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
completion:(FIRStorageVoidURLError)completion {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_completion = [completion copy];
}
return self;
}
- (void)dealloc {
[_fetcher stopFetching];
}
- (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary {
NSString *downloadTokens = dictionary[kFIRStorageMetadataDownloadTokens];
if (downloadTokens && downloadTokens.length > 0) {
NSArray<NSString *> *downloadTokenArray = [downloadTokens componentsSeparatedByString:@","];
NSString *bucket = dictionary[kFIRStorageMetadataBucket];
NSString *path = dictionary[kFIRStorageMetadataName];
NSString *fullPath = [NSString stringWithFormat:kFIRStorageFullPathFormat, bucket,
[FIRStorageUtils GCSEscapedString:path]];
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = self.reference.storage.scheme;
components.host = self.reference.storage.host;
components.port = self.reference.storage.port;
components.percentEncodedPath = fullPath;
// The backend can return an arbitrary number of download tokens, but we only expose the first
// token via the download URL.
NSURLQueryItem *altItem = [[NSURLQueryItem alloc] initWithName:@"alt" value:@"media"];
NSURLQueryItem *tokenItem = [[NSURLQueryItem alloc] initWithName:@"token"
value:downloadTokenArray[0]];
components.queryItems = @[ altItem, tokenItem ];
return [components URL];
}
return nil;
}
- (void)enqueue {
__weak FIRStorageGetDownloadURLTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageGetDownloadURLTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
request.HTTPMethod = @"GET";
request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime;
FIRStorageVoidURLError callback = strongSelf->_completion;
strongSelf->_completion = nil;
GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
strongSelf->_fetcher = fetcher;
fetcher.comment = @"GetDownloadURLTask";
strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
NSURL *downloadURL;
if (error) {
if (!self.error) {
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
}
} else {
NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data];
if (responseDictionary != nil) {
downloadURL = [strongSelf downloadURLFromMetadataDictionary:responseDictionary];
if (!downloadURL) {
self.error =
[FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL."];
}
} else {
self.error = [FIRStorageErrors errorWithInvalidRequest:data];
}
}
if (callback) {
callback(downloadURL, self.error);
}
self->_fetcherCompletion = nil;
};
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
FIRStorageGetDownloadURLTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
};
@end
@@ -0,0 +1,31 @@
/*
* 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.
*/
#import "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Task which provides the ability to get a download URL for an object in Firebase Storage.
*/
@interface FIRStorageGetDownloadURLTask ()
/** Extracts a download URL from the StorageMetadata dictonary representation. */
- (nullable NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,35 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h"
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
/**
* Task which provides the ability to get metadata on an object in Firebase Storage.
*/
@interface FIRStorageGetMetadataTask : FIRStorageTask <FIRStorageTaskManagement>
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
completion:(FIRStorageVoidMetadataError)completion;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,98 @@
// 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 "FirebaseStorage/Sources/FIRStorageGetMetadataTask.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h"
#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageUtils.h"
@implementation FIRStorageGetMetadataTask {
@private
FIRStorageVoidMetadataError _completion;
}
@synthesize fetcher = _fetcher;
@synthesize fetcherCompletion = _fetcherCompletion;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
completion:(FIRStorageVoidMetadataError)completion {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_completion = [completion copy];
}
return self;
}
- (void)dealloc {
[_fetcher stopFetching];
}
- (void)enqueue {
__weak FIRStorageGetMetadataTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageGetMetadataTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
request.HTTPMethod = @"GET";
request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime;
FIRStorageVoidMetadataError callback = strongSelf->_completion;
strongSelf->_completion = nil;
GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
strongSelf->_fetcher = fetcher;
fetcher.comment = @"GetMetadataTask";
strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
FIRStorageMetadata *metadata;
if (error) {
if (!self.error) {
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
}
} else {
NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data];
if (responseDictionary != nil) {
metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary];
[metadata setType:FIRStorageMetadataTypeFile];
} else {
self.error = [FIRStorageErrors errorWithInvalidRequest:data];
}
}
if (callback) {
callback(metadata, self.error);
}
self->_fetcherCompletion = nil;
};
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
FIRStorageGetMetadataTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
}
@end
@@ -0,0 +1,70 @@
// Copyright 2019 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
@implementation FIRStorageListResult
+ (nullable FIRStorageListResult *)fromDictionary:(NSDictionary<NSString *, id> *)dictionary
atReference:(FIRStorageReference *)reference {
NSMutableArray<FIRStorageReference *> *prefixes = [NSMutableArray new];
NSMutableArray<FIRStorageReference *> *items = [NSMutableArray new];
FIRStorageReference *rootReference = reference.root;
NSArray<NSString *> *prefixEntries = dictionary[kFIRStorageListPrefixes];
for (NSString *prefixEntry in prefixEntries) {
NSString *pathWithoutTrailingSlash = prefixEntry;
if ([prefixEntry hasSuffix:@"/"]) {
pathWithoutTrailingSlash = [pathWithoutTrailingSlash substringToIndex:prefixEntry.length - 1];
}
FIRStorageReference *prefixReference = [rootReference child:pathWithoutTrailingSlash];
[prefixes addObject:prefixReference];
}
NSArray<NSDictionary<NSString *, NSString *> *> *itemEntries = dictionary[kFIRStorageListItems];
for (NSDictionary<NSString *, NSString *> *itemEntry in itemEntries) {
FIRStorageReference *itemReference = [rootReference child:itemEntry[kFIRStorageListItemName]];
[items addObject:itemReference];
}
NSString *pageToken = dictionary[kFIRStorageListPageToken];
return [[FIRStorageListResult alloc] initWithPrefixes:prefixes items:items pageToken:pageToken];
}
- (nullable instancetype)initWithPrefixes:(NSArray<FIRStorageReference *> *)prefixes
items:(NSArray<FIRStorageReference *> *)items
pageToken:(nullable NSString *)pageToken {
self = [super init];
if (self) {
_prefixes = [prefixes copy];
_items = [items copy];
_pageToken = [pageToken copy];
}
return self;
}
- (instancetype)copyWithZone:(NSZone *)zone {
FIRStorageListResult *clone = [[[self class] allocWithZone:zone] initWithPrefixes:_prefixes
items:_items
pageToken:_pageToken];
return clone;
}
@end
@@ -0,0 +1,40 @@
/*
* Copyright 2019 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h"
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageListResult (Private)
/**
* Creates an instance of FIRStorageListResult with the contents of a dictionary.
*
* @param dictionary A dictionary containing the parsed JSON response from the backend.
* @param reference The FIRStorageReference that `list()` was called on.
* @return An instance of FIRStorageListResult that represents the contents of the dictionary.
*/
+ (nullable FIRStorageListResult *)fromDictionary:(NSDictionary<NSString *, id> *)dictionary
atReference:(FIRStorageReference *)reference;
/** Initializes a new FIRStorageListResult with the given data. */
- (nullable instancetype)initWithPrefixes:(NSArray<FIRStorageReference *> *)prefixes
items:(NSArray<FIRStorageReference *> *)items
pageToken:(nullable NSString *)pageToken;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,57 @@
/*
* Copyright 2019 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h"
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
/**
* Block typedef typically used in `list()` and `listAll()`.
* @param listResult The FIRStorageListResult returned by the operation, if it exists.
* @param error The error describing failure, if one occurred.
*/
typedef void (^FIRStorageVoidListError)(FIRStorageListResult *_Nullable listResult,
NSError *_Nullable error);
/** A Task that lists the entries under a {@link StorageReference} */
@interface FIRStorageListTask : FIRStorageTask <FIRStorageTaskManagement>
/**
* Initializes a new List Task.
*
* To schedule the task, invoke `[FIRStorageListTask enqueue]`.
*
* @param reference The location to invoke List on.
* @param service GTMSessionFetcherService to use for the RPC.
* @param queue The queue to schedule the List operation on.
* @param pageSize An optional pageSize, denoting the maximum size of the result set. If
* set to `nil`, the backend will use the default page size.
* @param previousPageToken An optional pageToken, used to resume a previous invocation.
* @param completion The completion handler to be called with the FIRStorageListResult.
*/
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
pageSize:(nullable NSNumber *)pageSize
previousPageToken:(nullable NSString *)previousPageToken
completion:(FIRStorageVoidListError)completion;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,126 @@
// Copyright 2019 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 "FirebaseStorage/Sources/FIRStorageListTask.h"
#import "FirebaseStorage/Sources/FIRStorageListResult_Private.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
@implementation FIRStorageListTask {
@private
FIRStorageVoidListError _completion;
NSNumber *_pageSize;
NSString *_previousPageToken;
}
@synthesize fetcher = _fetcher;
@synthesize fetcherCompletion = _fetcherCompletion;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
pageSize:(nullable NSNumber *)pageSize
previousPageToken:(nullable NSString *)previousPageToken
completion:(FIRStorageVoidListError)completion {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_completion = [completion copy];
_pageSize = pageSize;
_previousPageToken = [previousPageToken copy];
}
return self;
}
- (void)dealloc {
[_fetcher stopFetching];
}
- (void)enqueue {
__weak FIRStorageListTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageListTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSMutableDictionary<NSString *, NSString *> *queryParams = [NSMutableDictionary new];
NSString *prefix = [self reference].fullPath;
if (prefix.length != 0) {
queryParams[@"prefix"] = [prefix stringByAppendingString:@"/"];
}
// Firebase Storage uses file system semantics and treats slashes as separators. GCS's List API
// does not prescribe a separator, and hence we need to provide a slash as the delimiter.
queryParams[@"delimiter"] = @"/";
// listAll() doesn't set a pageSize as this allows Firebase Storage to determine how many items
// to return per page. This removes the need to backfill results if Firebase Storage filters
// objects that are considered invalid (such as items with two consecutive slashes).
if (strongSelf->_pageSize != nil) {
queryParams[@"maxResults"] = [strongSelf->_pageSize stringValue];
}
if (strongSelf->_previousPageToken) {
queryParams[@"pageToken"] = strongSelf->_previousPageToken;
}
FIRStorageReference *root = self.reference.root;
NSMutableURLRequest *request =
[[FIRStorageUtils defaultRequestForReference:root queryParams:queryParams] mutableCopy];
request.HTTPMethod = @"GET";
request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime;
FIRStorageVoidListError callback = strongSelf->_completion;
strongSelf->_completion = nil;
GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
strongSelf->_fetcher = fetcher;
fetcher.comment = @"ListTask";
strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
FIRStorageListResult *listResult;
if (error) {
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
} else {
NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data];
if (responseDictionary != nil) {
listResult = [FIRStorageListResult fromDictionary:responseDictionary
atReference:self.reference];
} else {
self.error = [FIRStorageErrors errorWithInvalidRequest:data];
}
}
if (callback) {
callback(listResult, self.error);
}
// Remove retain cycle set up by `strongSelf->_fetcherCompletion`
self->_fetcherCompletion = nil;
};
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
FIRStorageListTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
}
@end
@@ -0,0 +1,24 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
extern FIRLoggerService kFIRLoggerStorage;
// FIRStorageTokenAuthorizer.m
extern NSString *const kFIRStorageMessageCodeAppCheckError;
@@ -0,0 +1,22 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "FirebaseStorage/Sources/FIRStorageLogger.h"
FIRLoggerService kFIRLoggerStorage = @"[Firebase/Storage]";
// FIRStorageTokenAuthorizer.m
NSString *const kFIRStorageMessageCodeAppCheckError = @"I-STR000001";
@@ -0,0 +1,225 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h"
#import "FirebaseStorage/Sources/FIRStorageUtils.h"
// TODO: consider rewriting this using GTLR (GTLRStorageObjects.h)
@implementation FIRStorageMetadata
#pragma mark - Initializers
- (instancetype)init {
return [self initWithDictionary:[NSDictionary dictionary]];
}
- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
self = [super init];
if (self) {
_initialMetadata = [dictionary copy];
_bucket = dictionary[kFIRStorageMetadataBucket];
_cacheControl = dictionary[kFIRStorageMetadataCacheControl];
_contentDisposition = dictionary[kFIRStorageMetadataContentDisposition];
_contentEncoding = dictionary[kFIRStorageMetadataContentEncoding];
_contentLanguage = dictionary[kFIRStorageMetadataContentLanguage];
_contentType = dictionary[kFIRStorageMetadataContentType];
_customMetadata = dictionary[kFIRStorageMetadataCustomMetadata];
_size = [dictionary[kFIRStorageMetadataSize] longLongValue];
_generation = [dictionary[kFIRStorageMetadataGeneration] longLongValue];
_metageneration = [dictionary[kFIRStorageMetadataMetageneration] longLongValue];
_timeCreated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataTimeCreated]];
_updated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataUpdated]];
_md5Hash = dictionary[kFIRStorageMetadataMd5Hash];
// GCS "name" is our path, our "name" is just the last path component of the path
_path = dictionary[kFIRStorageMetadataName];
_name = [_path lastPathComponent];
}
return self;
}
#pragma mark - NSObject overrides
- (instancetype)copyWithZone:(NSZone *)zone {
FIRStorageMetadata *clone =
[[[self class] allocWithZone:zone] initWithDictionary:[self dictionaryRepresentation]];
clone.initialMetadata = [self.initialMetadata copy];
return clone;
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FIRStorageMetadata class]]) {
return NO;
}
BOOL isEqualObject = [self isEqualToFIRStorageMetadata:(FIRStorageMetadata *)object];
return isEqualObject;
}
- (BOOL)isEqualToFIRStorageMetadata:(FIRStorageMetadata *)metadata {
return [[self dictionaryRepresentation] isEqualToDictionary:[metadata dictionaryRepresentation]];
}
- (NSUInteger)hash {
NSUInteger hash = [[self dictionaryRepresentation] hash];
return hash;
}
- (NSString *)description {
NSDictionary *metadataDictionary = [self dictionaryRepresentation];
return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, metadataDictionary];
}
#pragma mark - Public methods
- (NSDictionary *)dictionaryRepresentation {
NSMutableDictionary *metadataDictionary = [[NSMutableDictionary alloc] initWithCapacity:13];
if (_bucket) {
metadataDictionary[kFIRStorageMetadataBucket] = _bucket;
}
if (_cacheControl) {
metadataDictionary[kFIRStorageMetadataCacheControl] = _cacheControl;
}
if (_contentDisposition) {
metadataDictionary[kFIRStorageMetadataContentDisposition] = _contentDisposition;
}
if (_contentEncoding) {
metadataDictionary[kFIRStorageMetadataContentEncoding] = _contentEncoding;
}
if (_contentLanguage) {
metadataDictionary[kFIRStorageMetadataContentLanguage] = _contentLanguage;
}
if (_contentType) {
metadataDictionary[kFIRStorageMetadataContentType] = _contentType;
}
if (_md5Hash) {
metadataDictionary[kFIRStorageMetadataMd5Hash] = _md5Hash;
}
if (_customMetadata) {
metadataDictionary[kFIRStorageMetadataCustomMetadata] = _customMetadata;
}
if (_generation) {
NSString *generationString = [NSString stringWithFormat:@"%lld", _generation];
metadataDictionary[kFIRStorageMetadataGeneration] = generationString;
}
if (_metageneration) {
NSString *metagenerationString = [NSString stringWithFormat:@"%lld", _metageneration];
metadataDictionary[kFIRStorageMetadataMetageneration] = metagenerationString;
}
if (_timeCreated) {
metadataDictionary[kFIRStorageMetadataTimeCreated] = [self RFC3339StringFromDate:_timeCreated];
}
if (_updated) {
metadataDictionary[kFIRStorageMetadataUpdated] = [self RFC3339StringFromDate:_updated];
}
if (_path) {
metadataDictionary[kFIRStorageMetadataName] = _path;
}
if (_size) {
metadataDictionary[kFIRStorageMetadataSize] = [NSNumber numberWithLongLong:_size];
}
return [metadataDictionary copy];
}
- (BOOL)isFile {
return _type == FIRStorageMetadataTypeFile;
}
- (BOOL)isFolder {
return _type == FIRStorageMetadataTypeFolder;
}
#pragma mark - Private methods
+ (void)removeMatchingMetadata:(NSMutableDictionary *)metadata
oldMetadata:(NSDictionary *)oldMetadata {
for (NSString *metadataKey in [oldMetadata allKeys]) {
id oldValue = [oldMetadata objectForKey:metadataKey];
id newValue = [metadata objectForKey:metadataKey];
if (oldValue && !newValue) {
[metadata setObject:[NSNull null] forKey:metadataKey];
} else if ([oldValue isKindOfClass:[NSString class]] &&
[newValue isKindOfClass:[NSString class]]) {
if ([oldValue isEqualToString:newValue]) {
[metadata removeObjectForKey:metadataKey];
}
} else if ([oldValue isKindOfClass:[NSDictionary class]] &&
[newValue isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *nestedMetadata = [newValue mutableCopy];
[self removeMatchingMetadata:nestedMetadata oldMetadata:oldValue];
[metadata setObject:[nestedMetadata copy] forKey:metadataKey];
}
}
}
- (NSDictionary *)updatedMetadata {
NSMutableDictionary *metadataUpdate = [[self dictionaryRepresentation] mutableCopy];
[FIRStorageMetadata removeMatchingMetadata:metadataUpdate oldMetadata:_initialMetadata];
return [metadataUpdate copy];
}
#pragma mark - RFC 3339 conversions
static NSDateFormatter *sRFC3339DateFormatter;
static void setupDateFormatterOnce(void) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
[sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
[sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSZZZZZ"];
[sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
});
}
- (nullable NSDate *)dateFromRFC3339String:(NSString *)dateString {
setupDateFormatterOnce();
NSDate *rfc3339Date = [sRFC3339DateFormatter dateFromString:dateString];
return rfc3339Date;
}
- (nullable NSString *)RFC3339StringFromDate:(NSDate *)date {
setupDateFormatterOnce();
NSString *rfc3339String = [sRFC3339DateFormatter stringFromDate:date];
return rfc3339String;
}
@end
@@ -0,0 +1,73 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
@class FIRStorageReference;
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageMetadata ()
@property(readwrite, nonatomic) NSString *name;
@property(readwrite, nonatomic) NSString *path;
@property(readwrite, nonatomic) FIRStorageReference *reference;
/**
* The type of the object, either a "File" or a "Folder".
*/
@property(readwrite) FIRStorageMetadataType type;
/**
* The original metadata representation received from the server or an empty dictionary
* if the metadata object was initialized by the user.
*/
@property(copy, nonatomic) NSDictionary *initialMetadata;
/**
* Recursively removes entries in 'metadata' that are unmodified from 'oldMetadata'.
* Adds 'NSNull' for entries that only exist in oldMetadata.
*/
+ (void)removeMatchingMetadata:(NSMutableDictionary *)metadata
oldMetadata:(NSDictionary *)oldMetadata;
/**
* Computes the updates between the state at initialization and the current state.
* Returns a dictionary with only the updated data. Removed keys are set to NSNull.
*/
- (NSDictionary *)updatedMetadata;
/**
* Returns an RFC3339 formatted date from a string.
* @param dateString An NSString of the form: yyyy-MM-ddTHH:mm:ss.SSSZ.
* @return An NSDate populated from the string or nil if conversion isn't possible.
*/
- (nullable NSDate *)dateFromRFC3339String:(NSString *)dateString;
/**
* Returns an RFC3339 formatted string from an NSDate object.
* @param date The NSDate object to be converted to a string.
* @return An NSString of the form: yyyy-MM-ddTHH:mm:ss.SSSZ or nil if conversion isn't possible.
*/
- (nullable NSString *)RFC3339StringFromDate:(NSDate *)date;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,215 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h"
#import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
@implementation FIRStorageObservableTask {
@private
// Handlers for pause, resume, progress, success, and failure callbacks
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_resumeHandlers;
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_pauseHandlers;
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_progressHandlers;
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_successHandlers;
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_failureHandlers;
// Reverse map of fetcher handles to status types
NSMutableDictionary<NSString *, NSNumber *> *_handleToStatusMap;
}
@synthesize state = _state;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_pauseHandlers = [[NSMutableDictionary alloc] init];
_resumeHandlers = [[NSMutableDictionary alloc] init];
_progressHandlers = [[NSMutableDictionary alloc] init];
_successHandlers = [[NSMutableDictionary alloc] init];
_failureHandlers = [[NSMutableDictionary alloc] init];
_handleToStatusMap = [[NSMutableDictionary alloc] init];
}
return self;
}
#pragma mark - Observers
- (FIRStorageHandle)observeStatus:(FIRStorageTaskStatus)status
handler:(FIRStorageVoidSnapshot)handler {
FIRStorageVoidSnapshot callback = handler;
// Note: self.snapshot is synchronized
FIRStorageTaskSnapshot *snapshot = self.snapshot;
// TODO: use an increasing counter instead of a random UUID
NSString *UUIDString = [[NSUUID UUID] UUIDString];
switch (status) {
case FIRStorageTaskStatusPause:
@synchronized(self) {
[_pauseHandlers setValue:callback forKey:UUIDString];
} // @synchronized(self)
if (_state == FIRStorageTaskStatePausing || _state == FIRStorageTaskStatePaused) {
[self fireHandlers:_pauseHandlers snapshot:snapshot];
}
break;
case FIRStorageTaskStatusResume:
@synchronized(self) {
[_resumeHandlers setValue:callback forKey:UUIDString];
} // @synchronized(self)
if (_state == FIRStorageTaskStateResuming || _state == FIRStorageTaskStateRunning) {
[self fireHandlers:_resumeHandlers snapshot:snapshot];
}
break;
case FIRStorageTaskStatusProgress:
@synchronized(self) {
[_progressHandlers setValue:callback forKey:UUIDString];
} // @synchronized(self)
if (_state == FIRStorageTaskStateRunning || _state == FIRStorageTaskStateProgress) {
[self fireHandlers:_progressHandlers snapshot:snapshot];
}
break;
case FIRStorageTaskStatusSuccess:
@synchronized(self) {
[_successHandlers setValue:callback forKey:UUIDString];
} // @synchronized(self)
if (_state == FIRStorageTaskStateSuccess) {
[self fireHandlers:_successHandlers snapshot:snapshot];
}
break;
case FIRStorageTaskStatusFailure:
@synchronized(self) {
[_failureHandlers setValue:callback forKey:UUIDString];
} // @synchronized(self)
if (_state == FIRStorageTaskStateFailing || _state == FIRStorageTaskStateFailed) {
[self fireHandlers:_failureHandlers snapshot:snapshot];
}
break;
case FIRStorageTaskStatusUnknown:
// Fall through to exception case if an unknown status is passed
default:
[NSException raise:NSInternalInconsistencyException
format:kFIRStorageInvalidObserverStatus, nil];
break;
}
@synchronized(self) {
_handleToStatusMap[UUIDString] = @(status);
} // @synchronized(self)
return UUIDString;
}
- (void)removeObserverWithHandle:(FIRStorageHandle)handle {
FIRStorageTaskStatus status = [_handleToStatusMap[handle] intValue];
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *observerDictionary =
[self handlerDictionaryForStatus:status];
@synchronized(self) {
[observerDictionary removeObjectForKey:handle];
[_handleToStatusMap removeObjectForKey:handle];
} // @synchronized(self)
}
- (void)removeAllObserversForStatus:(FIRStorageTaskStatus)status {
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *observerDictionary =
[self handlerDictionaryForStatus:status];
[self removeHandlersFromStatusMapForDictionary:observerDictionary];
@synchronized(self) {
[observerDictionary removeAllObjects];
} // @synchronized(self)
}
- (void)removeAllObservers {
@synchronized(self) {
[_pauseHandlers removeAllObjects];
[_resumeHandlers removeAllObjects];
[_progressHandlers removeAllObjects];
[_successHandlers removeAllObjects];
[_failureHandlers removeAllObjects];
[_handleToStatusMap removeAllObjects];
} // @synchronized(self)
}
- (NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *)handlerDictionaryForStatus:
(FIRStorageTaskStatus)status {
switch (status) {
case FIRStorageTaskStatusPause:
return _pauseHandlers;
case FIRStorageTaskStatusResume:
return _resumeHandlers;
case FIRStorageTaskStatusProgress:
return _progressHandlers;
case FIRStorageTaskStatusSuccess:
return _successHandlers;
case FIRStorageTaskStatusFailure:
return _failureHandlers;
case FIRStorageTaskStatusUnknown:
return [NSMutableDictionary dictionary];
default:
[NSException raise:NSInternalInconsistencyException
format:kFIRStorageInvalidObserverStatus, nil];
return nil;
}
}
- (void)removeHandlersFromStatusMapForDictionary:
(NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *)dict {
@synchronized(self) {
[_handleToStatusMap removeObjectsForKeys:dict.allKeys];
} // @synchronized(self)
}
- (void)fireHandlersForStatus:(FIRStorageTaskStatus)status
snapshot:(FIRStorageTaskSnapshot *)snapshot {
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *observerDictionary =
[self handlerDictionaryForStatus:status];
[self fireHandlers:observerDictionary snapshot:snapshot];
}
- (void)fireHandlers:(NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *)handlers
snapshot:(FIRStorageTaskSnapshot *)snapshot {
dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue;
if (!callbackQueue) {
callbackQueue = dispatch_get_main_queue();
}
// TODO: iterate over this list in a consistent order
NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *handlersCopy;
@synchronized(self) {
handlersCopy = [handlers copy];
} // @synchronized(self)
[handlersCopy
enumerateKeysAndObjectsUsingBlock:^(
NSString *_Nonnull key, FIRStorageVoidSnapshot _Nonnull handler, BOOL *_Nonnull stop) {
dispatch_async(callbackQueue, ^{
handler(snapshot);
});
}];
}
@end
@@ -0,0 +1,51 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h"
NS_ASSUME_NONNULL_BEGIN
@class FIRStorageReference;
@class FIRStorageTaskSnapshot;
@class GTMSessionFetcherService;
@interface FIRStorageObservableTask ()
/**
* Creates a new FIRStorageTask initialized with a FIRStorageReference and GTMSessionFetcherService.
* @param reference A FIRStorageReference the task will be performed on.
* @param service A GTMSessionFetcherService which provides the fetchers and configuration for
* requests.
* @param queue The shared queue to use for all Storage operations.
* @return A new FIRStorageTask representing the current task.
*/
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue;
/**
* Raise events for a given task status by passing along a snapshot of existing task state.
* @param status A FIRStorageTaskStatus to raise events for.
* @param snapshot A FIRStorageTaskSnapshot snapshot of task state to pass through the handler.
*/
- (void)fireHandlersForStatus:(FIRStorageTaskStatus)status
snapshot:(FIRStorageTaskSnapshot *)snapshot;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,106 @@
/*
* 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
/**
* Represents a path in GCS, which can be represented as: gs://bucket/path/to/object
* or http[s]://firebasestorage.googleapis.com/v0/b/bucket/o/path/to/object?token=<12345>
* This class also includes helper methods to parse those URI/Ls, as well as to
* add and remove path segments.
*/
@interface FIRStoragePath : NSObject
/**
* The GCS bucket in the path.
*/
@property(copy, nonatomic) NSString *bucket;
/**
* The GCS object in the path.
*/
@property(copy, nonatomic, nullable) NSString *object;
/**
* Parses a generic string (representing some URI or URL) and returns the appropriate path.
* @param string String which is parsed into a path.
* @return Returns an instance of FIRStoragePath or nil if one can't be created.
* @throws Throws an exception if the string is not a valid gs:// URI or http[s]:// URL.
*/
+ (nullable FIRStoragePath *)pathFromString:(NSString *)string;
/**
* Parses a gs://bucket/path/to/object URI into a GCS path.
* @param aURIString gs:// URI which is parsed into a path.
* @return Returns an instance of FIRStoragePath or nil if one can't be created.
* @throws Throws an exception if the string is not a valid gs:// URI.
*/
+ (nullable FIRStoragePath *)pathFromGSURI:(NSString *)aURIString;
- (instancetype)init NS_UNAVAILABLE;
/**
* Constructs an FIRStoragePath object that represents the given bucket and object.
* @param bucket The name of the bucket.
* @param object The name of the object.
* @return An instance of FIRStoragePath representing the @a bucket and @a object.
*/
- (instancetype)initWithBucket:(NSString *)bucket
object:(nullable NSString *)object NS_DESIGNATED_INITIALIZER;
/**
* Parses a http[s]://firebasestorage.googleapis.com/v0/b/bucket/o/path/to/object...?token=<12345>
* URL into a GCS path.
* @param aURLString http[s]:// URL which is parsed into a path.
* string which is parsed into a path.
* @return Returns an instance of FIRStoragePath or nil if one can't be created.
* @throws Throws an exception if the string is not a valid http[s]:// URL.
*/
+ (nullable FIRStoragePath *)pathFromHTTPURL:(NSString *)aURLString;
/**
* Creates a new path based off of the current path and a string appended to it.
* Note that all slashes are compressed to a single slash, and leading and trailing slashes
* are removed.
* @param path String to append to the current path.
* @return Returns a new instance of FIRStoragePath with the new path appended.
*/
- (FIRStoragePath *)child:(NSString *)path;
/**
* Creates a new path based off of the current path with the last path segment removed.
* @return Returns a new instance of FIRStoragePath pointing to the parent path,
* or nil if the current path points to the root.
*/
- (nullable FIRStoragePath *)parent;
/**
* Creates a new path based off of the root of the bucket.
* @return Returns a new instance of FIRStoragePath pointing to the root of the bucket.
*/
- (FIRStoragePath *)root;
/**
* Returns a GS URI representing the current path.
* @return Returns a gs://bucket/path/to/object URI representing the current path.
*/
- (NSString *)stringValue;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,195 @@
// 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 "FirebaseStorage/Sources/FIRStoragePath.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
@implementation FIRStoragePath
#pragma mark - Class methods
+ (nullable FIRStoragePath *)pathFromString:(NSString *)string {
if ([string hasPrefix:@"gs://"]) {
// "gs://bucket/path/to/object"
return [FIRStoragePath pathFromGSURI:string];
} else if ([string hasPrefix:@"http://"] || [string hasPrefix:@"https://"]) {
// "http[s]://firebasestorage.googleapis.com/bucket/path/to/object?signed_url_params"
return [FIRStoragePath pathFromHTTPURL:string];
} else {
// Invalid scheme, raise an exception!
[NSException raise:NSInternalInconsistencyException
format:@"URL scheme must be one of gs://, http://, or https:// "];
return nil;
}
}
+ (nullable FIRStoragePath *)pathFromGSURI:(NSString *)aURIString {
NSString *bucketName;
NSString *objectName;
NSScanner *scanner = [NSScanner scannerWithString:aURIString];
BOOL isGSURI = [scanner scanString:@"gs://" intoString:NULL];
BOOL hasBucket = [scanner scanUpToString:@"/" intoString:&bucketName];
[scanner scanString:@"/" intoString:NULL];
[scanner scanUpToString:@"\n" intoString:&objectName];
if (!isGSURI || !hasBucket) {
[NSException raise:NSInternalInconsistencyException
format:@"URI must be in the form of gs://<bucket>/<path/to/object>"];
return nil;
}
return [[self alloc] initWithBucket:bucketName object:objectName];
}
+ (nullable FIRStoragePath *)pathFromHTTPURL:(NSString *)aURLString {
NSString *bucketName;
NSString *objectName;
NSURL *httpsURL = [NSURL URLWithString:aURLString];
NSArray *pathComponents = httpsURL.pathComponents; // [/, v0, b, <bucket>, o, <objects/...>]
if ([pathComponents count] <= 3 || ![pathComponents[1] isEqual:@"v0"] ||
![pathComponents[2] isEqual:@"b"]) {
[NSException raise:NSInternalInconsistencyException
format:@"URL must be in the form of "
@"http[s]://<host>/v0/b/<bucket>/o/<path/to/"
@"object>[?token=signed_url_params]"];
return nil;
}
bucketName = pathComponents[3];
// Have an object name
if ([pathComponents count] > 5) {
NSRange objectRange = NSMakeRange(5, [pathComponents count] - 5);
objectName = [[pathComponents subarrayWithRange:objectRange] componentsJoinedByString:@"/"];
}
if (objectName.length == 0) {
objectName = nil;
}
return [[self alloc] initWithBucket:bucketName object:objectName];
}
#pragma mark - Initializers
- (instancetype)initWithBucket:(NSString *)bucket object:(nullable NSString *)object {
self = [super init];
if (self) {
_bucket = [bucket copy];
_object = [self standardizedPathForString:[object copy]];
}
return self;
}
#pragma mark - NSObject overrides
- (instancetype)copyWithZone:(NSZone *)zone {
return [[[self class] allocWithZone:zone] initWithBucket:_bucket object:_object];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FIRStoragePath class]]) {
return NO;
}
BOOL isObjectEqual = [self isEqualToFIRStoragePath:(FIRStoragePath *)object];
return isObjectEqual;
}
- (BOOL)isEqualToFIRStoragePath:(FIRStoragePath *)path {
BOOL isBucketEqual = _bucket == nil && path->_bucket == nil;
BOOL isObjectEqual = _object == nil && path->_object == nil;
if (_bucket && path->_bucket) {
isBucketEqual = [_bucket isEqual:path->_bucket];
}
if (_object && path.object) {
isObjectEqual = [_object isEqual:path->_object];
}
BOOL isEqual = isBucketEqual && isObjectEqual;
return isEqual;
}
- (NSUInteger)hash {
// "...because in those days, you could XOR anything with anything and get something useful..."
// https://www.usenix.org/system/files/1309_14-17_mickens.pdf
NSUInteger hash = [_bucket hash] ^ [_object hash];
return hash;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, [self stringValue]];
}
- (NSString *)stringValue {
return [NSString stringWithFormat:@"gs://%@/%@", _bucket, _object ?: @""];
}
#pragma mark - Public methods
- (FIRStoragePath *)child:(NSString *)path {
if (path.length == 0) {
return [self copy]; // Return a copy of the same path, nothing happened
}
NSString *childObject;
if (_object == nil) {
childObject = path;
} else {
childObject = [_object stringByAppendingPathComponent:path];
}
FIRStoragePath *childPath = [[FIRStoragePath alloc] initWithBucket:_bucket object:childObject];
return childPath;
}
- (nullable FIRStoragePath *)parent {
if (_object.length == 0) {
return nil;
}
NSString *parentObject = [_object stringByDeletingLastPathComponent];
FIRStoragePath *parentPath = [[FIRStoragePath alloc] initWithBucket:_bucket object:parentObject];
return parentPath;
}
- (FIRStoragePath *)root {
FIRStoragePath *rootPath = [[FIRStoragePath alloc] initWithBucket:_bucket object:nil];
return rootPath;
}
#pragma mark - Private methods
// Removes leading and trailing slashes, and compresses multiple slashes
// to create a canonical representation.
// Example: /foo//bar///baz//// -> foo/bar/baz
- (NSString *)standardizedPathForString:(NSString *)string {
NSMutableArray *components = [[string componentsSeparatedByString:@"/"] mutableCopy];
NSIndexSet *removedPaths =
[components indexesOfObjectsPassingTest:^BOOL(NSString *string, NSUInteger idx, BOOL *stop) {
return (string.length == 0);
}];
[components removeObjectsAtIndexes:removedPaths];
return [components componentsJoinedByString:@"/"];
}
@end
@@ -0,0 +1,492 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageDeleteTask.h"
#import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h"
#import "FirebaseStorage/Sources/FIRStorageGetMetadataTask.h"
#import "FirebaseStorage/Sources/FIRStorageListResult_Private.h"
#import "FirebaseStorage/Sources/FIRStorageListTask.h"
#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h"
#import "FirebaseStorage/Sources/FIRStorageUploadTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageUtils.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h"
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionFetcher.h>
#import <GTMSessionFetcher/GTMSessionFetcherService.h>
#endif
@implementation FIRStorageReference
- (instancetype)init {
FIRStorage *storage = [FIRStorage storage];
NSString *storageBucket = storage.app.options.storageBucket;
FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:storageBucket object:nil];
FIRStorageReference *reference = [self initWithStorage:storage path:path];
return reference;
}
- (instancetype)initWithStorage:(FIRStorage *)storage path:(FIRStoragePath *)path {
self = [super init];
if (self) {
_storage = storage;
_path = path;
}
return self;
}
#pragma mark - NSObject overrides
- (instancetype)copyWithZone:(NSZone *)zone {
FIRStorageReference *copiedReference = [[[self class] allocWithZone:zone] initWithStorage:_storage
path:_path];
return copiedReference;
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FIRStorageReference class]]) {
return NO;
}
BOOL isObjectEqual = [self isEqualToFIRStorageReference:(FIRStorageReference *)object];
return isObjectEqual;
}
- (BOOL)isEqualToFIRStorageReference:(FIRStorageReference *)reference {
BOOL isEqual = [_storage isEqual:reference.storage] && [_path isEqual:reference.path];
return isEqual;
}
- (NSUInteger)hash {
NSUInteger hash = [_storage hash] ^ [_path hash];
return hash;
}
- (NSString *)description {
return [self stringValue];
}
- (NSString *)stringValue {
NSString *value = [NSString stringWithFormat:@"gs://%@/%@", _path.bucket, _path.object ?: @""];
return value;
}
#pragma mark - Property Getters
- (NSString *)bucket {
NSString *bucket = _path.bucket;
return bucket;
}
- (NSString *)fullPath {
NSString *path = _path.object;
if (!path) {
path = @"";
}
return path;
}
- (NSString *)name {
NSString *name = [_path.object lastPathComponent];
if (!name) {
name = @"";
}
return name;
}
#pragma mark - Path Operations
- (FIRStorageReference *)root {
FIRStoragePath *rootPath = [_path root];
FIRStorageReference *rootReference = [[FIRStorageReference alloc] initWithStorage:_storage
path:rootPath];
return rootReference;
}
- (nullable FIRStorageReference *)parent {
FIRStoragePath *parentPath = [_path parent];
if (!parentPath) {
return nil;
}
FIRStorageReference *parentReference = [[FIRStorageReference alloc] initWithStorage:_storage
path:parentPath];
return parentReference;
}
- (FIRStorageReference *)child:(NSString *)path {
FIRStoragePath *childPath = [_path child:path];
FIRStorageReference *childReference = [[FIRStorageReference alloc] initWithStorage:_storage
path:childPath];
return childReference;
}
#pragma mark - Uploads
- (FIRStorageUploadTask *)putData:(NSData *)uploadData {
return [self putData:uploadData metadata:nil completion:nil];
}
- (FIRStorageUploadTask *)putData:(NSData *)uploadData
metadata:(nullable FIRStorageMetadata *)metadata {
return [self putData:uploadData metadata:metadata completion:nil];
}
- (FIRStorageUploadTask *)putData:(NSData *)uploadData
metadata:(nullable FIRStorageMetadata *)metadata
completion:(nullable FIRStorageVoidMetadataError)completion {
if (!metadata) {
metadata = [[FIRStorageMetadata alloc] init];
}
metadata.path = _path.object;
metadata.name = [_path.object lastPathComponent];
FIRStorageUploadTask *task =
[[FIRStorageUploadTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
data:uploadData
metadata:metadata];
if (completion) {
__block BOOL completed = NO;
dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
if (!callbackQueue) {
callbackQueue = dispatch_get_main_queue();
}
[task observeStatus:FIRStorageTaskStatusSuccess
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(snapshot.metadata, nil);
}
});
}];
[task observeStatus:FIRStorageTaskStatusFailure
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(nil, snapshot.error);
}
});
}];
}
[task enqueue];
return task;
}
- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL {
return [self putFile:fileURL metadata:nil completion:nil];
}
- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
metadata:(nullable FIRStorageMetadata *)metadata {
return [self putFile:fileURL metadata:metadata completion:nil];
}
- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
metadata:(nullable FIRStorageMetadata *)metadata
completion:(nullable FIRStorageVoidMetadataError)completion {
if (!metadata) {
metadata = [[FIRStorageMetadata alloc] init];
}
metadata.path = _path.object;
metadata.name = [_path.object lastPathComponent];
FIRStorageUploadTask *task =
[[FIRStorageUploadTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
file:fileURL
metadata:metadata];
if (completion) {
__block BOOL completed = NO;
dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
if (!callbackQueue) {
callbackQueue = dispatch_get_main_queue();
}
[task observeStatus:FIRStorageTaskStatusSuccess
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(snapshot.metadata, nil);
}
});
}];
[task observeStatus:FIRStorageTaskStatusFailure
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(nil, snapshot.error);
}
});
}];
}
[task enqueue];
return task;
}
#pragma mark - Downloads
- (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size
completion:(FIRStorageVoidDataError)completion {
__block BOOL completed = NO;
FIRStorageDownloadTask *task =
[[FIRStorageDownloadTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
file:nil];
dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
if (!callbackQueue) {
callbackQueue = dispatch_get_main_queue();
}
[task observeStatus:FIRStorageTaskStatusSuccess
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
FIRStorageDownloadTask *task = snapshot.task;
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(task.downloadData, nil);
}
});
}];
[task observeStatus:FIRStorageTaskStatusFailure
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(nil, snapshot.error);
}
});
}];
[task
observeStatus:FIRStorageTaskStatusProgress
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
FIRStorageDownloadTask *task = snapshot.task;
if (task.progress.totalUnitCount > size || task.progress.completedUnitCount > size) {
NSDictionary *infoDictionary =
@{@"totalSize" : @(task.progress.totalUnitCount),
@"maxAllowedSize" : @(size)};
NSError *error =
[FIRStorageErrors errorWithCode:FIRStorageErrorCodeDownloadSizeExceeded
infoDictionary:infoDictionary];
[task cancelWithError:error];
}
}];
[task enqueue];
return task;
}
- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL {
return [self writeToFile:fileURL completion:nil];
}
- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL
completion:(FIRStorageVoidURLError)completion {
FIRStorageDownloadTask *task =
[[FIRStorageDownloadTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
file:fileURL];
if (completion) {
__block BOOL completed = NO;
dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
if (!callbackQueue) {
callbackQueue = dispatch_get_main_queue();
}
[task observeStatus:FIRStorageTaskStatusSuccess
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(fileURL, nil);
}
});
}];
[task observeStatus:FIRStorageTaskStatusFailure
handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
dispatch_async(callbackQueue, ^{
if (!completed) {
completed = YES;
completion(nil, snapshot.error);
}
});
}];
}
[task enqueue];
return task;
}
- (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion {
FIRStorageGetDownloadURLTask *task =
[[FIRStorageGetDownloadURLTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
completion:completion];
[task enqueue];
}
#pragma mark - List
- (void)listWithMaxResults:(int64_t)maxResults completion:(FIRStorageVoidListError)completion {
if (maxResults <= 0 || maxResults > 1000) {
completion(nil,
[FIRStorageUtils storageErrorWithDescription:
@"Argument 'maxResults' must be between 1 and 1000 inclusive."
code:FIRStorageErrorCodeInvalidArgument]);
} else {
FIRStorageListTask *task =
[[FIRStorageListTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
pageSize:@(maxResults)
previousPageToken:nil
completion:completion];
[task enqueue];
}
}
- (void)listWithMaxResults:(int64_t)maxResults
pageToken:(NSString *)pageToken
completion:(FIRStorageVoidListError)completion {
if (maxResults <= 0 || maxResults > 1000) {
completion(nil,
[FIRStorageUtils storageErrorWithDescription:
@"Argument 'maxResults' must be between 1 and 1000 inclusive."
code:FIRStorageErrorCodeInvalidArgument]);
} else {
FIRStorageListTask *task =
[[FIRStorageListTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
pageSize:@(maxResults)
previousPageToken:pageToken
completion:completion];
[task enqueue];
}
}
- (void)listAllWithCompletion:(FIRStorageVoidListError)completion {
NSMutableArray *prefixes = [NSMutableArray new];
NSMutableArray *items = [NSMutableArray new];
__weak FIRStorageReference *weakSelf = self;
__block FIRStorageVoidListError paginatedCompletion =
^(FIRStorageListResult *listResult, NSError *error) {
if (error) {
completion(nil, error);
return;
}
FIRStorageReference *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[prefixes addObjectsFromArray:listResult.prefixes];
[items addObjectsFromArray:listResult.items];
if (listResult.pageToken) {
FIRStorageListTask *nextPage = [[FIRStorageListTask alloc]
initWithReference:self
fetcherService:strongSelf->_storage.fetcherServiceForApp
dispatchQueue:strongSelf->_storage.dispatchQueue
pageSize:nil
previousPageToken:listResult.pageToken
completion:paginatedCompletion];
[nextPage enqueue];
} else {
FIRStorageListResult *result = [[FIRStorageListResult alloc] initWithPrefixes:prefixes
items:items
pageToken:nil];
// Break the retain cycle we set up indirectly by passing the callback to `nextPage`.
paginatedCompletion = nil;
completion(result, nil);
}
};
FIRStorageListTask *task =
[[FIRStorageListTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
pageSize:nil
previousPageToken:nil
completion:paginatedCompletion];
[task enqueue];
}
#pragma mark - Metadata Operations
- (void)metadataWithCompletion:(FIRStorageVoidMetadataError)completion {
FIRStorageGetMetadataTask *task =
[[FIRStorageGetMetadataTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
completion:completion];
[task enqueue];
}
- (void)updateMetadata:(FIRStorageMetadata *)metadata
completion:(nullable FIRStorageVoidMetadataError)completion {
FIRStorageUpdateMetadataTask *task =
[[FIRStorageUpdateMetadataTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
metadata:metadata
completion:completion];
[task enqueue];
}
#pragma mark - Delete
- (void)deleteWithCompletion:(nullable FIRStorageVoidError)completion {
FIRStorageDeleteTask *task =
[[FIRStorageDeleteTask alloc] initWithReference:self
fetcherService:_storage.fetcherServiceForApp
dispatchQueue:_storage.dispatchQueue
completion:completion];
[task enqueue];
}
@end
@@ -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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/FIRStoragePath.h"
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageReference ()
@property(nonatomic, readwrite) FIRStorage *storage;
/**
* The current path which points to an object in the Google Cloud Storage bucket.
*/
@property(strong, nonatomic) FIRStoragePath *path;
- (instancetype)initWithStorage:(FIRStorage *)storage
path:(FIRStoragePath *)path NS_DESIGNATED_INITIALIZER;
- (NSString *)stringValue;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,73 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionFetcherService.h>
#endif
@implementation FIRStorageTask
- (instancetype)init {
@throw [NSException exceptionWithName:@"Attempt to call unavailable initializer."
reason:@"init unavailable, use designated initializer"
userInfo:nil];
}
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue {
self = [super init];
if (self) {
_reference = reference;
_baseRequest = [FIRStorageUtils defaultRequestForReference:reference];
_fetcherService = service;
_fetcherService.maxRetryInterval = _reference.storage.maxOperationRetryInterval;
_dispatchQueue = queue;
}
return self;
}
- (FIRStorageTaskSnapshot *)snapshot {
@synchronized(self) {
NSProgress *progress = [NSProgress progressWithTotalUnitCount:self.progress.totalUnitCount];
progress.completedUnitCount = self.progress.completedUnitCount;
FIRStorageTaskSnapshot *snapshot =
[[FIRStorageTaskSnapshot alloc] initWithTask:self
state:self.state
metadata:self.metadata
reference:self.reference
progress:progress
error:[self.error copy]];
return snapshot;
}
}
- (void)dispatchAsync:(void (^)(void))block {
dispatch_async(self.dispatchQueue, block);
}
@end
@@ -0,0 +1,88 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h"
#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
@implementation FIRStorageTaskSnapshot
- (instancetype)initWithTask:(__kindof FIRStorageTask *)task
state:(FIRStorageTaskState)state
metadata:(nullable FIRStorageMetadata *)metadata
reference:(FIRStorageReference *)reference
progress:(nullable NSProgress *)progress
error:(nullable NSError *)error {
self = [super init];
if (self) {
_task = task;
_metadata = metadata;
_reference = reference;
_progress = progress;
_error = error;
switch (state) {
case FIRStorageTaskStateQueueing:
case FIRStorageTaskStateRunning:
case FIRStorageTaskStateResuming:
_status = FIRStorageTaskStatusResume;
break;
case FIRStorageTaskStateProgress:
_status = FIRStorageTaskStatusProgress;
break;
case FIRStorageTaskStatePaused:
case FIRStorageTaskStatePausing:
_status = FIRStorageTaskStatusPause;
break;
case FIRStorageTaskStateSuccess:
case FIRStorageTaskStateCompleting:
_status = FIRStorageTaskStatusSuccess;
break;
case FIRStorageTaskStateCancelled:
case FIRStorageTaskStateFailing:
case FIRStorageTaskStateFailed:
_status = FIRStorageTaskStatusFailure;
break;
default:
_status = FIRStorageTaskStatusUnknown;
}
}
return self;
}
- (NSString *)description {
switch (_status) {
case FIRStorageTaskStatusResume:
return @"<State: Resume>";
case FIRStorageTaskStatusProgress:
return [NSString stringWithFormat:@"<State: Progress, Progress: %@>", _progress];
case FIRStorageTaskStatusPause:
return @"<State: Paused>";
case FIRStorageTaskStatusSuccess:
return @"<State: Success>";
case FIRStorageTaskStatusFailure:
return [NSString stringWithFormat:@"<State: Failed, Error: %@>", _error];
default:
return @"<State: Unknown>";
};
}
@end
@@ -0,0 +1,60 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
NS_ASSUME_NONNULL_BEGIN
@class FIRStorageMetadata;
@class FIRStorageReference;
@class FIRStorageTask;
@interface FIRStorageTaskSnapshot ()
@property(readwrite, copy, nonatomic) FIRStorageTask *task;
@property(readwrite, copy, nonatomic) FIRStorageMetadata *metadata;
@property(readwrite, copy, nonatomic) FIRStorageReference *reference;
@property(readwrite, strong, nonatomic) NSProgress *progress;
@property(readwrite, copy, nonatomic) NSError *error;
/**
* Creates a new task snapshot from the given properties.
* @param task The task being represented in this snapshot.
* @param state The current state of the parent task.
* @param metadata The FIRStorageMetadata of a task. Before upload/update, contains the metadata
* to be updated; after, contains the returned metadata. May be nil if no metadata is provided
* or returned.
* @param reference The FIRStorageReference that spawned the task this snapshot is based on.
* @param progress An NSProgress object containing progress of the task this snapshot is based on,
* or nil if the task doesn't report progress.
* @param error An NSError object containing an error that occurred during the task,
* if one occurred.
* @return Returns the constructed snapshot.
*/
- (instancetype)initWithTask:(__kindof FIRStorageTask *)task
state:(FIRStorageTaskState)state
metadata:(nullable FIRStorageMetadata *)metadata
reference:(FIRStorageReference *)reference
progress:(nullable NSProgress *)progress
error:(nullable NSError *)error;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,96 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageErrors.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h"
#import "FirebaseStorage/Sources/FIRStorageUtils.h"
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionFetcher.h>
#import <GTMSessionFetcher/GTMSessionFetcherService.h>
#endif
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageTask ()
/**
* State for the current task in progress.
*/
@property(atomic) FIRStorageTaskState state;
/**
* FIRStorageMetadata for the task in progress, or nil if none present.
*/
@property(strong, nonatomic, nullable) FIRStorageMetadata *metadata;
/**
* Error which occurred during task execution, or nil if no error occurred.
*/
@property(strong, nonatomic, nullable) NSError *error;
/**
* NSProgress object which tracks the progress of an observable task.
*/
@property(strong, nonatomic) NSProgress *progress;
/**
* Reference pointing to the location the task is being performed against.
*/
@property(strong, nonatomic) FIRStorageReference *reference;
/**
* A serial queue for all storage operations.
*/
@property(nonatomic, readonly) dispatch_queue_t dispatchQueue;
@property(strong, readwrite, nonatomic, nonnull) FIRStorageTaskSnapshot *snapshot;
@property(readonly, copy, nonatomic) NSURLRequest *baseRequest;
@property(strong, atomic) GTMSessionFetcher *fetcher;
@property(readonly, nonatomic) GTMSessionFetcherService *fetcherService;
@property(readonly, copy) GTMSessionFetcherCompletionHandler fetcherCompletion;
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a new FIRStorageTask initialized with a FIRStorageReference and GTMSessionFetcherService.
* @param reference A FIRStorageReference the task will be performed on.
* @param service A GTMSessionFetcherService which provides the fetchers and configuration for
* requests.
* @param queue The shared queue to use for all Storage operations.
* @return A new FIRStorageTask representing the current task.
*/
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;
/** Dispatches a block on the shared Storage queue. */
- (void)dispatchAsync:(void (^)(void))block;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,54 @@
/*
* 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.
*/
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionFetcherService.h>
#endif
@protocol FIRAuthInterop;
@protocol FIRAppCheckInterop;
NS_ASSUME_NONNULL_BEGIN
/**
* Wrapper class for FIRAuthInterop that implements the GTMFetcherAuthorizationProtocol,
* so as to easily provide GTMSessionFetcher fetches a Firebase Authentication JWT
* for the current logged in user. Handles token expiration and other failure cases.
* If no authentication provider exists or no token is found, no token is added
* and the request is passed.
*/
@interface FIRStorageTokenAuthorizer : NSObject <GTMFetcherAuthorizationProtocol>
/**
* Initializes the token authorizer with an instance of FIRApp.
* @param googleAppID The Google AppID of the app to send with the request.
* @param auth An instance that provides access to Auth functionality, if it exists.
* @param appCheck An instance that provides access to AppCheck functionality, if it exists.
* @return Returns an instance of FIRStorageTokenAuthorizer which adds the appropriate
* "Authorization" header to all outbound requests. Note that a token may not be added
* if the Auth instance is nil. This allows for unauthenticated access, if Firebase
* Storage rules allow for it.
*/
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
fetcherService:(GTMSessionFetcherService *)service
authProvider:(nullable id<FIRAuthInterop>)auth
appCheck:(nullable id<FIRAppCheckInterop>)appCheck;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,166 @@
// 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 "FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h"
#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageErrors.h"
#import "FirebaseStorage/Sources/FIRStorageLogger.h"
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h"
#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h"
#import "Interop/Auth/Public/FIRAuthInterop.h"
static NSString *const kAppCheckTokenHeader = @"X-Firebase-AppCheck";
static NSString *const kAuthHeader = @"Authorization";
@implementation FIRStorageTokenAuthorizer {
@private
/// Google App ID to pass along with each request.
NSString *_googleAppID;
/// Auth provider.
id<FIRAuthInterop> _auth;
id<FIRAppCheckInterop> _appCheck;
}
@synthesize fetcherService = _fetcherService;
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
fetcherService:(GTMSessionFetcherService *)service
authProvider:(nullable id<FIRAuthInterop>)auth
appCheck:(nullable id<FIRAppCheckInterop>)appCheck {
self = [super init];
if (self) {
_googleAppID = googleAppID;
_fetcherService = service;
_auth = auth;
_appCheck = appCheck;
}
return self;
}
#pragma mark - GTMFetcherAuthorizationProtocol methods
- (void)authorizeRequest:(NSMutableURLRequest *)request
delegate:(id)delegate
didFinishSelector:(SEL)sel {
// Set version header on each request
NSString *versionString = [NSString stringWithFormat:@"ios/%@", FIRFirebaseVersion()];
[request setValue:versionString forHTTPHeaderField:@"x-firebase-storage-version"];
// Set GMP ID on each request
[request setValue:_googleAppID forHTTPHeaderField:@"x-firebase-gmpid"];
if (delegate && sel) {
id selfParam = self;
NSMethodSignature *sig = [delegate methodSignatureForSelector:sel];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setSelector:sel];
[invocation setTarget:delegate];
[invocation setArgument:&selfParam atIndex:2];
[invocation setArgument:&request atIndex:3];
dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue;
if (!callbackQueue) {
callbackQueue = dispatch_get_main_queue();
}
[invocation retainArguments];
dispatch_group_t fetchTokenGroup = dispatch_group_create();
if (_auth) {
dispatch_group_enter(fetchTokenGroup);
[_auth getTokenForcingRefresh:NO
withCallback:^(NSString *_Nullable token, NSError *_Nullable error) {
if (error) {
NSMutableDictionary *errorDictionary =
[NSMutableDictionary dictionaryWithDictionary:error.userInfo];
errorDictionary[kFIRStorageResponseErrorDomain] = error.domain;
errorDictionary[kFIRStorageResponseErrorCode] = @(error.code);
NSError *tokenError =
[FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnauthenticated
infoDictionary:errorDictionary];
[invocation setArgument:&tokenError atIndex:4];
} else if (token) {
NSString *firebaseToken =
[NSString stringWithFormat:kFIRStorageAuthTokenFormat, token];
[request setValue:firebaseToken forHTTPHeaderField:kAuthHeader];
}
dispatch_group_leave(fetchTokenGroup);
}];
}
if (_appCheck) {
dispatch_group_enter(fetchTokenGroup);
[_appCheck getTokenForcingRefresh:NO
completion:^(id<FIRAppCheckTokenResultInterop> tokenResult) {
[request setValue:tokenResult.token
forHTTPHeaderField:kAppCheckTokenHeader];
if (tokenResult.error) {
FIRLogDebug(kFIRLoggerStorage, kFIRStorageMessageCodeAppCheckError,
@"Failed to fetch AppCheck token. Error: %@",
tokenResult.error);
}
dispatch_group_leave(fetchTokenGroup);
}];
}
dispatch_group_notify(fetchTokenGroup, callbackQueue, ^{
[invocation invoke];
});
}
}
// Note that stopAuthorization, isAuthorizingRequest, and userEmail
// aren't relevant with the Firebase App/Auth implementation of tokens,
// and thus aren't implemented. Token refresh is handled transparently
// for us, and we don't allow the auth request to be stopped.
// Auth is also not required so the world doesn't stop.
- (void)stopAuthorization {
// Noop
}
- (void)stopAuthorizationForRequest:(NSURLRequest *)request {
// Noop
}
- (BOOL)isAuthorizingRequest:(NSURLRequest *)request {
return NO;
}
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request {
NSString *authHeader = request.allHTTPHeaderFields[@"Authorization"];
BOOL isFirebaseToken = [authHeader hasPrefix:@"Firebase"];
return isFirebaseToken;
}
- (NSString *)userEmail {
// Noop
return nil;
}
@end
@@ -0,0 +1,36 @@
/*
* 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h"
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
/**
* Task which provides the ability update the metadata on an object in Firebase Storage.
*/
@interface FIRStorageUpdateMetadataTask : FIRStorageTask <FIRStorageTaskManagement>
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
metadata:(FIRStorageMetadata *)metadata
completion:(FIRStorageVoidMetadataError)completion;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,107 @@
// 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 "FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h"
#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
@implementation FIRStorageUpdateMetadataTask {
@private
FIRStorageVoidMetadataError _completion;
// Metadata used in the update request
FIRStorageMetadata *_updateMetadata;
}
@synthesize fetcher = _fetcher;
@synthesize fetcherCompletion = _fetcherCompletion;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
metadata:(FIRStorageMetadata *)metadata
completion:(FIRStorageVoidMetadataError)completion {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_updateMetadata = [metadata copy];
_completion = [completion copy];
}
return self;
}
- (void)dealloc {
[_fetcher stopFetching];
}
- (void)enqueue {
__weak FIRStorageUpdateMetadataTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageUpdateMetadataTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
NSDictionary *updateDictionary = [strongSelf->_updateMetadata updatedMetadata];
NSData *updateData = [NSData frs_dataFromJSONDictionary:updateDictionary];
request.HTTPMethod = @"PATCH";
request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime;
request.HTTPBody = updateData;
NSString *typeString = @"application/json; charset=UTF-8";
[request setValue:typeString forHTTPHeaderField:@"Content-Type"];
NSString *lengthString = [NSString stringWithFormat:@"%zu", (unsigned long)[updateData length]];
[request setValue:lengthString forHTTPHeaderField:@"Content-Length"];
FIRStorageVoidMetadataError callback = strongSelf->_completion;
strongSelf->_completion = nil;
GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
strongSelf->_fetcher = fetcher;
strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
FIRStorageMetadata *metadata;
if (error) {
if (!self.error) {
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
}
} else {
NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data];
if (responseDictionary) {
metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary];
[metadata setType:FIRStorageMetadataTypeFile];
} else {
self.error = [FIRStorageErrors errorWithInvalidRequest:data];
}
}
if (callback) {
callback(metadata, self.error);
}
self->_fetcherCompletion = nil;
};
fetcher.comment = @"UpdateMetadataTask";
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
FIRStorageUpdateMetadataTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
}
@end
@@ -0,0 +1,277 @@
// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h"
#import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorageUploadTask_Private.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionUploadFetcher.h>
#endif
@implementation FIRStorageUploadTask
@synthesize progress = _progress;
@synthesize fetcherCompletion = _fetcherCompletion;
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
data:(NSData *)uploadData
metadata:(FIRStorageMetadata *)metadata {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_uploadMetadata = [metadata copy];
_uploadData = [uploadData copy];
_progress = [NSProgress progressWithTotalUnitCount:[_uploadData length]];
if (!_uploadMetadata.contentType) {
_uploadMetadata.contentType = @"application/octet-stream";
}
}
return self;
}
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
file:(NSURL *)fileURL
metadata:(FIRStorageMetadata *)metadata {
self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
if (self) {
_uploadMetadata = [metadata copy];
_fileURL = [fileURL copy];
_progress = [NSProgress progressWithTotalUnitCount:0];
NSString *mimeType = [FIRStorageUtils MIMETypeForExtension:[_fileURL pathExtension]];
if (!_uploadMetadata.contentType) {
_uploadMetadata.contentType = mimeType ?: @"application/octet-stream";
}
}
return self;
}
- (void)dealloc {
[_uploadFetcher stopFetching];
}
- (void)enqueue {
__weak FIRStorageUploadTask *weakSelf = self;
[self dispatchAsync:^() {
FIRStorageUploadTask *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSError *contentValidationError;
if (![strongSelf isContentToUploadValid:&contentValidationError]) {
strongSelf.error = contentValidationError;
[strongSelf finishTaskWithStatus:FIRStorageTaskStatusFailure snapshot:strongSelf.snapshot];
return;
}
strongSelf.state = FIRStorageTaskStateQueueing;
NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
request.HTTPMethod = @"POST";
request.timeoutInterval = strongSelf.reference.storage.maxUploadRetryTime;
NSData *bodyData =
[NSData frs_dataFromJSONDictionary:[strongSelf->_uploadMetadata dictionaryRepresentation]];
request.HTTPBody = bodyData;
[request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
NSString *contentLengthString =
[NSString stringWithFormat:@"%zu", (unsigned long)[bodyData length]];
[request setValue:contentLengthString forHTTPHeaderField:@"Content-Length"];
NSURLComponents *components = [NSURLComponents componentsWithURL:request.URL
resolvingAgainstBaseURL:NO];
if ([components.host isEqual:kGCSHost]) {
[components setPercentEncodedPath:[@"/upload" stringByAppendingString:components.path]];
}
NSDictionary *queryParams = @{@"uploadType" : @"resumable", @"name" : self.uploadMetadata.path};
[components setPercentEncodedQuery:[FIRStorageUtils queryStringForDictionary:queryParams]];
request.URL = components.URL;
GTMSessionUploadFetcher *uploadFetcher =
[GTMSessionUploadFetcher uploadFetcherWithRequest:request
uploadMIMEType:strongSelf->_uploadMetadata.contentType
chunkSize:kGTMSessionUploadFetcherStandardChunkSize
fetcherService:self.fetcherService];
if (strongSelf->_uploadData) {
[uploadFetcher setUploadData:strongSelf->_uploadData];
uploadFetcher.comment = @"Data UploadTask";
} else if (strongSelf->_fileURL) {
[uploadFetcher setUploadFileURL:strongSelf->_fileURL];
uploadFetcher.comment = @"File UploadTask";
}
uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryInterval;
[uploadFetcher setSendProgressBlock:^(int64_t bytesSent, int64_t totalBytesSent,
int64_t totalBytesExpectedToSend) {
weakSelf.state = FIRStorageTaskStateProgress;
weakSelf.progress.completedUnitCount = totalBytesSent;
weakSelf.progress.totalUnitCount = totalBytesExpectedToSend;
weakSelf.metadata = self->_uploadMetadata;
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:weakSelf.snapshot];
weakSelf.state = FIRStorageTaskStateRunning;
}];
strongSelf->_uploadFetcher = uploadFetcher;
// Process fetches
strongSelf.state = FIRStorageTaskStateRunning;
strongSelf->_fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) {
// Fire last progress updates
[self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot];
// Handle potential issues with upload
if (error) {
self.state = FIRStorageTaskStateFailed;
self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
self.metadata = self->_uploadMetadata;
[self finishTaskWithStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot];
return;
}
// Upload completed successfully, fire completion callbacks
self.state = FIRStorageTaskStateSuccess;
NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data];
if (responseDictionary) {
FIRStorageMetadata *metadata =
[[FIRStorageMetadata alloc] initWithDictionary:responseDictionary];
[metadata setType:FIRStorageMetadataTypeFile];
self.metadata = metadata;
} else {
self.error = [FIRStorageErrors errorWithInvalidRequest:data];
}
[self finishTaskWithStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot];
};
[strongSelf->_uploadFetcher
beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) {
FIRStorageUploadTask *strongSelf = weakSelf;
if (strongSelf.fetcherCompletion) {
strongSelf.fetcherCompletion(data, error);
}
}];
}];
}
- (void)finishTaskWithStatus:(FIRStorageTaskStatus)status
snapshot:(FIRStorageTaskSnapshot *)snapshot {
[self fireHandlersForStatus:status snapshot:self.snapshot];
[self removeAllObservers];
self->_fetcherCompletion = nil;
}
- (BOOL)isContentToUploadValid:(NSError **)outError {
if (_uploadData != nil) {
return YES;
}
NSError *fileReachabilityError;
if (![_fileURL checkResourceIsReachableAndReturnError:&fileReachabilityError] ||
![self fileURLisFile:_fileURL]) {
if (outError != NULL) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:2];
userInfo[NSLocalizedDescriptionKey] = [NSString
stringWithFormat:@"File at URL: %@ is not reachable. "
@"Ensure file URL is not a directory, symbolic link, or invalid url.",
_fileURL.absoluteString];
if (fileReachabilityError) {
userInfo[NSUnderlyingErrorKey] = fileReachabilityError;
}
*outError = [NSError errorWithDomain:FIRStorageErrorDomain
code:FIRStorageErrorCodeUnknown
userInfo:userInfo];
}
return NO;
}
return YES;
}
#pragma mark - Upload Management
- (void)cancel {
__weak FIRStorageUploadTask *weakSelf = self;
[self dispatchAsync:^() {
weakSelf.state = FIRStorageTaskStateCancelled;
[weakSelf.uploadFetcher stopFetching];
if (weakSelf.state != FIRStorageTaskStateSuccess) {
weakSelf.metadata = weakSelf.uploadMetadata;
}
weakSelf.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled];
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot];
}];
}
- (void)pause {
__weak FIRStorageUploadTask *weakSelf = self;
[self dispatchAsync:^() {
weakSelf.state = FIRStorageTaskStatePaused;
[weakSelf.uploadFetcher pauseFetching];
if (weakSelf.state != FIRStorageTaskStateSuccess) {
weakSelf.metadata = weakSelf.uploadMetadata;
}
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:weakSelf.snapshot];
}];
}
- (void)resume {
__weak FIRStorageUploadTask *weakSelf = self;
[self dispatchAsync:^() {
weakSelf.state = FIRStorageTaskStateResuming;
[weakSelf.uploadFetcher resumeFetching];
if (weakSelf.state != FIRStorageTaskStateSuccess) {
weakSelf.metadata = weakSelf.uploadMetadata;
}
[weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:weakSelf.snapshot];
weakSelf.state = FIRStorageTaskStateRunning;
}];
}
#pragma mark - Private Helpers
- (BOOL)fileURLisFile:(NSURL *)fileURL {
NSNumber *isFile = [NSNumber numberWithBool:NO];
[fileURL getResourceValue:&isFile forKey:NSURLIsRegularFileKey error:nil];
return [isFile boolValue];
}
@end
@@ -0,0 +1,73 @@
/*
* 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.
*/
@class GTMSessionUploadFetcher;
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorageUploadTask ()
/**
* The data to be uploaded (if uploading bytes).
*/
@property(readonly, copy, nonatomic, nullable) NSData *uploadData;
/**
* The name of a file on disk to be uploaded (if uploading from a file).
*/
@property(readonly, copy, nonatomic, nullable) NSURL *fileURL;
/**
* The FIRStorageMetadata about the object being uploaded.
*/
@property(readonly, copy, nonatomic) FIRStorageMetadata *uploadMetadata;
/**
* GTMSessionUploadFetcher used by all uploads.
*/
@property(strong, atomic) GTMSessionUploadFetcher *uploadFetcher;
/**
* Initializes an upload task with a base FIRStorageReference and GTMSessionFetcherService.
* @param reference The base FIRStorageReference which fetchers use for configuration.
* @param service The GTMSessionFetcherService which will create fetchers.
* @param queue The shared queue to use for all Storage operations.
* @param uploadData The NSData object to be uploaded.
* @return Returns an instance of FIRStorageUploadTask.
*/
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
data:(NSData *)uploadData
metadata:(FIRStorageMetadata *)metadata;
/**
* Initializes an upload task with a base FIRStorageReference and GTMSessionFetcherService.
* @param reference The base FIRStorageReference which fetchers use for configuration.
* @param service The GTMSessionFetcherService which will create fetchers.
* @param queue The shared queue to use for all Storage operations.
* @param fileURL The system file URL to upload from.
* @return Returns an instance of FIRStorageUploadTask.
*/
- (instancetype)initWithReference:(FIRStorageReference *)reference
fetcherService:(GTMSessionFetcherService *)service
dispatchQueue:(dispatch_queue_t)queue
file:(NSURL *)fileURL
metadata:(FIRStorageMetadata *)metadata;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,122 @@
/*
* 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 FIRStoragePath;
@class FIRStorageReference;
NS_ASSUME_NONNULL_BEGIN
/**
* FIRStorageUtils provides a number of helper methods for commonly used operations
* in Firebase Storage, such as JSON parsing, escaping, and file extensions.
*/
@interface FIRStorageUtils : NSObject
/**
* Returns a percent encoded string appropriate for GCS.
* See https://cloud.google.com/storage/docs/naming for more details.
* @param string A path to escape characters according to the GCS
* @return A percent encoded string appropriate for GCS operations or nil if string is nil
* or can't be escaped.
*/
+ (nullable NSString *)GCSEscapedString:(NSString *)string;
/**
* Returns the MIME type for a file extension.
* Example of how to get MIME type here: http://ddeville.me/2011/12/mime-to-UTI-cocoa/
* @param extension A file extension such as "txt", "png", etc.
* @return The MIME type for the input extension such as "text/plain", "image/png", etc.
* or nil if no type is found.
*/
+ (nullable NSString *)MIMETypeForExtension:(NSString *)extension;
/**
* Returns a properly escaped query string from a given dictionary of query items to values.
* @param dictionary A dictionary containing query items and associated values.
* @return A properly escaped query string or the empty string for a nil or empty dictionary.
*/
+ (NSString *)queryStringForDictionary:(nullable NSDictionary *)dictionary;
/**
* Returns a base NSURLRequest used by all tasks.
* @param reference The FIRStorageReference to create a request for.
* @return Returns a properly formatted NSURLRequest of the form:
* scheme://host/version/b/<bucket>/o[/path/to/object]
*/
+ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference;
/**
* Returns a base NSURLRequest with custom query parameters.
* @param reference The FIRStorageReference to create a request for.
* @param queryParams A key/value dictionary with query parameters.
* @return Returns a formatted NSURLRequest
*/
+ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference
queryParams:(NSDictionary<NSString *, NSString *> *)queryParams;
/**
* Creates the appropriate GCS percent escaped path for a given FIRStoragePath.
* @param path The FIRStoragePath to encode.
* @return Returns the GCS encoded URL for a given FIRStoragePath.
*/
+ (NSString *)encodedURLForPath:(FIRStoragePath *)path;
/**
* Creates a NSError in the Firebase Storage domain with given code and description.
* Useful for argument validation.
* @param description The error description to surface to the user.
* @param code The error code.
* @return An NSError in the Firebase Storage error domain.
*/
+ (NSError *)storageErrorWithDescription:(NSString *)description code:(NSInteger)code;
/**
* Performs a crude translation of the user provided timeouts to the retry intervals that
* GTMSessionFetcher accepts. GTMSessionFetcher times out operations if the time between individual
* retry attempts exceed a certain threshold, while our API contract looks at the total observed
* time of the operation (i.e. the sum of all retries).
* @param retryTime A timeout that caps the sum of all retry attempts
* @return A timeout that caps the timeout of the last retry attempt
*/
+ (NSTimeInterval)computeRetryIntervalFromRetryTime:(NSTimeInterval)retryTime;
@end
@interface NSDictionary (FIRStorageNSDictionaryJSONHelpers)
/**
* Returns a dictionary representation of the data in @a data.
* @param data NSData containing JSON data.
* @return An NSDictionary representation of the JSON, or nil if serialization failed.
*/
+ (nullable instancetype)frs_dictionaryFromJSONData:(nullable NSData *)data;
@end
@interface NSData (FIRStorageNSDataJSONHelpers)
/**
* Returns an NSData instance containing JSON serialized from @a dictionary.
* @param dictionary An NSDictionary containing only types serializable to JSON.
* @return An NSData object representing the binary JSON, or nil if serialization failed.
*/
+ (nullable instancetype)frs_dataFromJSONDictionary:(nullable NSDictionary *)dictionary;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,182 @@
// 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>
#if TARGET_OS_IOS || TARGET_OS_TV
#import <MobileCoreServices/MobileCoreServices.h>
#elif TARGET_OS_OSX || TARGET_OS_WATCH
#import <CoreServices/CoreServices.h>
#endif
#import "FirebaseStorage/Sources/FIRStorageUtils.h"
#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
#import "FirebaseStorage/Sources/FIRStorageErrors.h"
#import "FirebaseStorage/Sources/FIRStoragePath.h"
#import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
#if SWIFT_PACKAGE
@import GTMSessionFetcherCore;
#else
#import <GTMSessionFetcher/GTMSessionFetcher.h>
#endif
// This is the list at https://cloud.google.com/storage/docs/json_api/ without &, ; and +.
NSString *const kGCSObjectAllowedCharacterSet =
@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*,=:@";
@implementation FIRStorageUtils
+ (nullable NSString *)GCSEscapedString:(NSString *)string {
NSCharacterSet *allowedCharacters =
[NSCharacterSet characterSetWithCharactersInString:kGCSObjectAllowedCharacterSet];
return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
}
+ (nullable NSString *)MIMETypeForExtension:(NSString *)extension {
if (extension == nil) {
return nil;
}
CFStringRef pathExtension = (__bridge_retained CFStringRef)extension;
CFStringRef type =
UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL);
NSString *mimeType =
(__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType);
CFRelease(pathExtension);
if (type != NULL) {
CFRelease(type);
}
return mimeType;
}
+ (NSString *)queryStringForDictionary:(nullable NSDictionary *)dictionary {
if (!dictionary) {
return @"";
}
__block NSMutableArray *queryItems = [[NSMutableArray alloc] initWithCapacity:[dictionary count]];
[dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull name, NSString *_Nonnull value,
BOOL *_Nonnull stop) {
NSString *item =
[FIRStorageUtils GCSEscapedString:[NSString stringWithFormat:@"%@=%@", name, value]];
[queryItems addObject:item];
}];
return [queryItems componentsJoinedByString:@"&"];
}
+ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSURLComponents *components = [[NSURLComponents alloc] init];
[components setScheme:reference.storage.scheme];
[components setHost:reference.storage.host];
[components setPort:reference.storage.port];
NSString *encodedPath = [self encodedURLForPath:reference.path];
[components setPercentEncodedPath:encodedPath];
[request setURL:components.URL];
return request;
}
+ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference
queryParams:(NSDictionary<NSString *, NSString *> *)queryParams {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSURLComponents *components = [[NSURLComponents alloc] init];
[components setScheme:reference.storage.scheme];
[components setHost:reference.storage.host];
[components setPort:reference.storage.port];
NSMutableArray<NSURLQueryItem *> *queryItems = [NSMutableArray new];
for (NSString *key in queryParams) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:queryParams[key]]];
}
[components setQueryItems:queryItems];
// NSURLComponents does not encode "+" as "%2B". This is however required by our backend, as
// it treats "+" as a shorthand encoding for spaces. See also
// https://stackoverflow.com/questions/31577188/how-to-encode-into-2b-with-nsurlcomponents
[components setPercentEncodedQuery:[[components percentEncodedQuery]
stringByReplacingOccurrencesOfString:@"+"
withString:@"%2B"]];
NSString *encodedPath = [self encodedURLForPath:reference.path];
[components setPercentEncodedPath:encodedPath];
[request setURL:components.URL];
return request;
}
+ (NSString *)encodedURLForPath:(FIRStoragePath *)path {
NSString *bucketName = [FIRStorageUtils GCSEscapedString:path.bucket];
NSString *objectName = [FIRStorageUtils GCSEscapedString:path.object];
NSString *bucketFormat = [NSString stringWithFormat:kFIRStorageBucketPathFormat, bucketName];
NSString *urlPath = [@"/" stringByAppendingPathComponent:bucketFormat];
if (objectName) {
NSString *objectFormat = [NSString stringWithFormat:kFIRStorageObjectPathFormat, objectName];
urlPath = [urlPath stringByAppendingFormat:@"/%@", objectFormat];
} else {
urlPath = [urlPath stringByAppendingString:@"/o"];
}
return [@"/" stringByAppendingString:[kFIRStorageVersionPath stringByAppendingString:urlPath]];
}
+ (NSError *)storageErrorWithDescription:(NSString *)description code:(NSInteger)code {
return [NSError errorWithDomain:FIRStorageErrorDomain
code:code
userInfo:@{NSLocalizedDescriptionKey : description}];
}
+ (NSTimeInterval)computeRetryIntervalFromRetryTime:(NSTimeInterval)retryTime {
// GTMSessionFetcher's retry starts at 1 second and then doubles every time. We use this
// information to compute a best-effort estimate of what to translate the user provided retry
// time into.
// Note that this is the same as 2 << (log2(retryTime) - 1), but deemed more readable.
NSTimeInterval lastInterval = 1.0;
NSTimeInterval sumOfAllIntervals = 1.0;
while (sumOfAllIntervals < retryTime) {
lastInterval *= 2;
sumOfAllIntervals += lastInterval;
}
return lastInterval;
}
@end
@implementation NSDictionary (FIRStorageNSDictionaryJSONHelpers)
+ (nullable instancetype)frs_dictionaryFromJSONData:(nullable NSData *)data {
if (!data) {
return nil;
}
return [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];
}
@end
@implementation NSData (FIRStorageNSDataJSONHelpers)
+ (nullable instancetype)frs_dataFromJSONDictionary:(nullable NSDictionary *)dictionary {
if (!dictionary) {
return nil;
}
return [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil];
}
@end
@@ -0,0 +1,70 @@
/*
* 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.
*/
@class FIRApp;
@class GTMSessionFetcherService;
NS_ASSUME_NONNULL_BEGIN
@interface FIRStorage ()
@property(strong, nonatomic, readwrite) FIRApp *app;
@property(strong, nonatomic, nullable) GTMSessionFetcherService *fetcherServiceForApp;
@property(nonatomic, readonly) dispatch_queue_t dispatchQueue;
@property(strong, nonatomic) NSString *storageBucket;
@property(strong, nonatomic) NSString *scheme;
@property(strong, nonatomic) NSString *host;
@property(strong, nonatomic) NSNumber *port;
/**
* Maximum time between retry attempts for uploads.
*
* This is used by GTMSessionFetcher and translated from the user provided `maxUploadRetryTime`.
*/
@property(assign, nonatomic) NSTimeInterval maxUploadRetryInterval;
/**
* Maximum time between retry attempts for downloads.
*
* This is used by GTMSessionFetcher and translated from the user provided `maxDownloadRetryTime`.
*/
@property(assign, nonatomic) NSTimeInterval maxDownloadRetryInterval;
/**
* Maximum time between retry attempts for any operation that is not an upload or download.
*
* This is used by GTMSessionFetcher and translated from the user provided `maxOperationRetryTime`.
*/
@property(assign, nonatomic) NSTimeInterval maxOperationRetryInterval;
/**
* Enables/disables GTMSessionFetcher HTTP logging
* @param isLoggingEnabled Boolean passed through to enable/disable GTMSessionFetcher logging
*/
+ (void)setGTMSessionFetcherLoggingEnabled:(BOOL)isLoggingEnabled;
/** Configures the storage instance. Freezes the host setting. */
- (void)ensureConfigured;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,132 @@
/*
* 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 "FIRStorageConstants.h"
@class FIRApp;
@class FIRStorageReference;
NS_ASSUME_NONNULL_BEGIN
/**
* FirebaseStorage is a service that supports uploading and downloading binary objects,
* such as images, videos, and other files to Google Cloud Storage.
*
* If you call [FIRStorage storage], the instance will initialize with the default FIRApp,
* [FIRApp defaultApp], and the storage location will come from the provided
* GoogleService-Info.plist.
*
* If you call [FIRStorage storageForApp:] and provide a custom instance of FIRApp,
* the storage location will be specified via the FIROptions#storageBucket property.
*/
NS_SWIFT_NAME(Storage)
@interface FIRStorage : NSObject
/**
* Creates an instance of FIRStorage, configured with the default FIRApp.
* @return the FIRStorage instance, initialized with the default FIRApp.
*/
+ (instancetype)storage NS_SWIFT_NAME(storage());
/**
* Creates an instance of FIRStorage, configured with the custom FIRApp @a app.
* @param app The custom FIRApp used for initialization.
* @return the FIRStorage instance, initialized with the custom FIRApp.
*/
+ (instancetype)storageForApp:(FIRApp *)app NS_SWIFT_NAME(storage(app:));
/**
* Creates an instance of FIRStorage, configured with a custom storage bucket @a url.
* @param url The gs:// url to your Firebase Storage Bucket.
* @return the FIRStorage instance, initialized with the custom FIRApp.
*/
+ (instancetype)storageWithURL:(NSString *)url NS_SWIFT_NAME(storage(url:));
/**
* Creates an instance of FIRStorage, configured with a custom FIRApp @a app and a custom storage
* bucket @a url.
* @param app The custom FIRApp used for initialization.
* @param url The gs:// url to your Firebase Storage Bucket.
* @return the FIRStorage instance, initialized with the custom FIRApp.
*/
+ (instancetype)storageForApp:(FIRApp *)app URL:(NSString *)url NS_SWIFT_NAME(storage(app:url:));
- (instancetype)init NS_UNAVAILABLE;
/**
* The Firebase App associated with this Firebase Storage instance.
*/
@property(strong, nonatomic, readonly) FIRApp *app;
/**
* Maximum time in seconds to retry an upload if a failure occurs.
* Defaults to 10 minutes (600 seconds).
*/
@property NSTimeInterval maxUploadRetryTime;
/**
* Maximum time in seconds to retry a download if a failure occurs.
* Defaults to 10 minutes (600 seconds).
*/
@property NSTimeInterval maxDownloadRetryTime;
/**
* Maximum time in seconds to retry operations other than upload and download if a failure occurs.
* Defaults to 2 minutes (120 seconds).
*/
@property NSTimeInterval maxOperationRetryTime;
/**
* Queue that all developer callbacks are fired on. Defaults to the main queue.
*/
@property(strong, nonatomic) dispatch_queue_t callbackQueue;
/**
* Creates a FIRStorageReference initialized at the root Firebase Storage location.
* @return An instance of FIRStorageReference initialized at the root.
*/
- (FIRStorageReference *)reference;
/**
* Creates a FIRStorageReference given a gs:// or https:// URL pointing to a Firebase Storage
* location. For example, you can pass in an https:// download URL retrieved from
* [FIRStorageReference downloadURLWithCompletion] or the gs:// URI from
* [FIRStorageReference description].
* @param string A gs:// or https:// URL to initialize the reference with.
* @return An instance of FIRStorageReference at the given child path.
* @throws Throws an exception if passed in URL is not associated with the FIRApp used to initialize
* this FIRStorage.
*/
- (FIRStorageReference *)referenceForURL:(NSString *)string;
/**
* Creates a FIRStorageReference initialized at a child Firebase Storage location.
* @param string A relative path from the root to initialize the reference with,
* for instance @"path/to/object".
* @return An instance of FIRStorageReference at the given child path.
*/
- (FIRStorageReference *)referenceWithPath:(NSString *)string;
/**
* Configures the Storage SDK to use an emulated backend instead of the default remote backend.
*/
- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,174 @@
/*
* 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 FIRStorageDownloadTask;
@class FIRStorageMetadata;
@class FIRStorageTaskSnapshot;
@class FIRStorageUploadTask;
NS_ASSUME_NONNULL_BEGIN
/**
* NSString typedef representing a task listener handle.
*/
typedef NSString *FIRStorageHandle NS_SWIFT_NAME(StorageHandle);
/**
* Block typedef typically used when downloading data.
* @param data The data returned by the download, or nil if no data available or download failed.
* @param error The error describing failure, if one occurred.
*/
typedef void (^FIRStorageVoidDataError)(NSData *_Nullable data, NSError *_Nullable error)
NS_SWIFT_NAME(StorageVoidDataError);
/**
* Block typedef typically used when performing "binary" async operations such as delete,
* where the operation either succeeds without an error or fails with an error.
* @param error The error describing failure, if one occurred.
*/
typedef void (^FIRStorageVoidError)(NSError *_Nullable error) NS_SWIFT_NAME(StorageVoidError);
/**
* Block typedef typically used when retrieving metadata.
* @param metadata The metadata returned by the operation, if metadata exists.
*/
typedef void (^FIRStorageVoidMetadata)(FIRStorageMetadata *_Nullable metadata)
NS_SWIFT_NAME(StorageVoidMetadata);
/**
* Block typedef typically used when retrieving metadata with the possibility of an error.
* @param metadata The metadata returned by the operation, if metadata exists.
* @param error The error describing failure, if one occurred.
*/
typedef void (^FIRStorageVoidMetadataError)(FIRStorageMetadata *_Nullable metadata,
NSError *_Nullable error)
NS_SWIFT_NAME(StorageVoidMetadataError);
/**
* Block typedef typically used to asynchronously return a storage task snapshot.
* @param snapshot The returned task snapshot.
*/
typedef void (^FIRStorageVoidSnapshot)(FIRStorageTaskSnapshot *snapshot)
NS_SWIFT_NAME(StorageVoidSnapshot);
/**
* Block typedef typically used when retrieving a download URL.
* @param URL The download URL associated with the operation.
* @param error The error describing failure, if one occurred.
*/
typedef void (^FIRStorageVoidURLError)(NSURL *_Nullable URL, NSError *_Nullable error)
NS_SWIFT_NAME(StorageVoidURLError);
/**
* Enum representing the upload and download task status.
*/
typedef NS_ENUM(NSInteger, FIRStorageTaskStatus) {
/**
* Unknown task status.
*/
FIRStorageTaskStatusUnknown,
/**
* Task is being resumed.
*/
FIRStorageTaskStatusResume,
/**
* Task reported a progress event.
*/
FIRStorageTaskStatusProgress,
/**
* Task is paused.
*/
FIRStorageTaskStatusPause,
/**
* Task has completed successfully.
*/
FIRStorageTaskStatusSuccess,
/**
* Task has failed and is unrecoverable.
*/
FIRStorageTaskStatusFailure
} NS_SWIFT_NAME(StorageTaskStatus);
/**
* Firebase Storage error domain.
*/
FOUNDATION_EXPORT NSString *const FIRStorageErrorDomain NS_SWIFT_NAME(StorageErrorDomain);
/**
* Enum representing the errors raised by Firebase Storage.
*/
typedef NS_ENUM(NSInteger, FIRStorageErrorCode) {
/** An unknown error occurred. */
FIRStorageErrorCodeUnknown = -13000,
/** No object exists at the desired reference. */
FIRStorageErrorCodeObjectNotFound = -13010,
/** No bucket is configured for Firebase Storage. */
FIRStorageErrorCodeBucketNotFound = -13011,
/** No project is configured for Firebase Storage. */
FIRStorageErrorCodeProjectNotFound = -13012,
/**
* Quota on your Firebase Storage bucket has been exceeded.
* If you're on the free tier, upgrade to a paid plan.
* If you're on a paid plan, reach out to Firebase support.
*/
FIRStorageErrorCodeQuotaExceeded = -13013,
/** User is unauthenticated. Authenticate and try again. */
FIRStorageErrorCodeUnauthenticated = -13020,
/**
* User is not authorized to perform the desired action.
* Check your rules to ensure they are correct.
*/
FIRStorageErrorCodeUnauthorized = -13021,
/**
* The maximum time limit on an operation (upload, download, delete, etc.) has been exceeded.
* Try uploading again.
*/
FIRStorageErrorCodeRetryLimitExceeded = -13030,
/**
* File on the client does not match the checksum of the file received by the server.
* Try uploading again.
*/
FIRStorageErrorCodeNonMatchingChecksum = -13031,
/**
* Size of the downloaded file exceeds the amount of memory allocated for the download.
* Increase memory cap and try downloading again.
*/
FIRStorageErrorCodeDownloadSizeExceeded = -13032,
/** User cancelled the operation. */
FIRStorageErrorCodeCancelled = -13040,
/** An invalid argument was provided. */
FIRStorageErrorCodeInvalidArgument = -13050
} NS_SWIFT_NAME(StorageErrorCode);
NS_ASSUME_NONNULL_END
@@ -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>
#import "FIRStorageObservableTask.h"
NS_ASSUME_NONNULL_BEGIN
/**
* FIRStorageDownloadTask implements resumable downloads from an object in Firebase Storage.
* Downloads can be returned on completion with a completion handler, and can be monitored
* by attaching observers, or controlled by calling FIRStorageTask#pause, FIRStorageTask#resume,
* or FIRStorageTask#cancel.
* Downloads can currently be returned as NSData in memory, or as an NSURL to a file on disk.
* Downloads are performed on a background queue, and callbacks are raised on the developer
* specified callbackQueue in FIRStorage, or the main queue if left unspecified.
* Currently all uploads must be initiated and managed on the main queue.
*/
NS_SWIFT_NAME(StorageDownloadTask)
@interface FIRStorageDownloadTask : FIRStorageObservableTask <FIRStorageTaskManagement>
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,53 @@
/*
* Copyright 2019 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 FIRStorageReference;
NS_ASSUME_NONNULL_BEGIN
/** Contains the prefixes and items returned by a `StorageReference.list()` call. */
NS_SWIFT_NAME(StorageListResult)
@interface FIRStorageListResult : NSObject <NSCopying>
- (instancetype)init NS_UNAVAILABLE;
/**
* The prefixes (folders) returned by the `list()` operation.
*
* @return A list of prefixes (folders).
*/
@property(nonatomic, readonly) NSArray<FIRStorageReference *> *prefixes;
/**
* The items (files) returned by the `list()` operation.
*
* @return A list of items (files).
*/
@property(nonatomic, readonly) NSArray<FIRStorageReference *> *items;
/**
* Returns a token that can be used to resume a previous `list()` operation. `nil`
* indicates that there are no more results.
*
* @return A page token if more results are available.
*/
@property(nonatomic, readonly, nullable) NSString *pageToken;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,140 @@
/*
* 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 FIRStorageReference;
NS_ASSUME_NONNULL_BEGIN
/**
* Class which represents the metadata on an object in Firebase Storage. This metadata is
* returned on successful operations, and can be used to retrieve download URLs, content types,
* and a FIRStorage reference to the object in question. Full documentation can be found at the GCS
* Objects#resource docs.
* @see https://cloud.google.com/storage/docs/json_api/v1/objects#resource
*/
NS_SWIFT_NAME(StorageMetadata)
@interface FIRStorageMetadata : NSObject <NSCopying>
/**
* The name of the bucket containing this object.
*/
@property(copy, nonatomic, readonly) NSString *bucket;
/**
* Cache-Control directive for the object data.
*/
@property(copy, nonatomic, nullable) NSString *cacheControl;
/**
* Content-Disposition of the object data.
*/
@property(copy, nonatomic, nullable) NSString *contentDisposition;
/**
* Content-Encoding of the object data.
*/
@property(copy, nonatomic, nullable) NSString *contentEncoding;
/**
* Content-Language of the object data.
*/
@property(copy, nonatomic, nullable) NSString *contentLanguage;
/**
* Content-Type of the object data.
*/
@property(copy, nonatomic, nullable) NSString *contentType;
/**
* MD5 hash of the data; encoded using base64.
*/
@property(copy, nonatomic, nullable, readonly) NSString *md5Hash;
/**
* The content generation of this object. Used for object versioning.
*/
@property(readonly) int64_t generation;
/**
* User-provided metadata, in key/value pairs.
*/
@property(copy, nonatomic, nullable) NSDictionary<NSString *, NSString *> *customMetadata;
/**
* The version of the metadata for this object at this generation. Used
* for preconditions and for detecting changes in metadata. A metageneration number is only
* meaningful in the context of a particular generation of a particular object.
*/
@property(readonly) int64_t metageneration;
/**
* The name of this object, in gs://bucket/path/to/object.txt, this is object.txt.
*/
@property(copy, nonatomic, readonly, nullable) NSString *name;
/**
* The full path of this object, in gs://bucket/path/to/object.txt, this is path/to/object.txt.
*/
@property(copy, nonatomic, readonly, nullable) NSString *path;
/**
* Content-Length of the data in bytes.
*/
@property(readonly) int64_t size;
/**
* The creation time of the object in RFC 3339 format.
*/
@property(copy, nonatomic, readonly, nullable) NSDate *timeCreated;
/**
* The modification time of the object metadata in RFC 3339 format.
*/
@property(copy, nonatomic, readonly, nullable) NSDate *updated;
/**
* A reference to the object in Firebase Storage.
*/
@property(strong, nonatomic, readonly, nullable) FIRStorageReference *storageReference;
/**
* Creates an instance of FIRStorageMetadata from the contents of a dictionary.
* @return An instance of FIRStorageMetadata that represents the contents of a dictionary.
*/
- (nullable instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionary
NS_DESIGNATED_INITIALIZER;
/**
* Creates an NSDictionary from the contents of the metadata.
* @return An NSDictionary that represents the contents of the metadata.
*/
- (NSDictionary<NSString *, id> *)dictionaryRepresentation;
/**
* Determines if the current metadata represents a "file".
*/
@property(readonly, getter=isFile) BOOL file;
/**
* Determines if the current metadata represents a "folder".
*/
@property(readonly, getter=isFolder) BOOL folder;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,62 @@
/*
* 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 "FIRStorageTask.h"
NS_ASSUME_NONNULL_BEGIN
@class FIRStorageReference;
@class FIRStorageTaskSnapshot;
/**
* Extends FIRStorageTask to provide observable semantics such as adding and removing observers.
* Observers produce a FIRStorageHandle, which is used to keep track of and remove specific
* observers at a later date.
* This class is currently not thread safe and can only be called on the main thread.
*/
NS_SWIFT_NAME(StorageObservableTask)
@interface FIRStorageObservableTask : FIRStorageTask
/**
* Observes changes in the upload status: Resume, Pause, Progress, Success, and Failure.
* @param status The FIRStorageTaskStatus change to observe.
* @param handler A callback that fires every time the status event occurs,
* returns a FIRStorageTaskSnapshot containing the state of the task.
* @return A task handle that can be used to remove the observer at a later date.
*/
- (FIRStorageHandle)observeStatus:(FIRStorageTaskStatus)status
handler:(void (^)(FIRStorageTaskSnapshot *snapshot))handler;
/**
* Removes the single observer with the provided handle.
* @param handle The handle of the task to remove.
*/
- (void)removeObserverWithHandle:(FIRStorageHandle)handle;
/**
* Removes all observers for a single status.
* @param status A FIRStorageTaskStatus to remove listeners for.
*/
- (void)removeAllObserversForStatus:(FIRStorageTaskStatus)status;
/**
* Removes all observers.
*/
- (void)removeAllObservers;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,315 @@
/*
* 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 "FIRStorage.h"
#import "FIRStorageConstants.h"
#import "FIRStorageDownloadTask.h"
#import "FIRStorageListResult.h"
#import "FIRStorageMetadata.h"
#import "FIRStorageTask.h"
#import "FIRStorageUploadTask.h"
NS_ASSUME_NONNULL_BEGIN
/**
* FIRStorageReference represents a reference to a Google Cloud Storage object. Developers can
* upload and download objects, as well as get/set object metadata, and delete an object at the
* path.
* @see https://cloud.google.com/storage/
*/
NS_SWIFT_NAME(StorageReference)
@interface FIRStorageReference : NSObject
/**
* The FIRStorage service object which created this reference.
*/
@property(nonatomic, readonly) FIRStorage *storage;
/**
* The name of the Google Cloud Storage bucket associated with this reference,
* in gs://bucket/path/to/object.txt, the bucket would be: 'bucket'
*/
@property(nonatomic, readonly) NSString *bucket;
/**
* The full path to this object, not including the Google Cloud Storage bucket.
* In gs://bucket/path/to/object.txt, the full path would be: 'path/to/object.txt'
*/
@property(nonatomic, readonly) NSString *fullPath;
/**
* The short name of the object associated with this reference,
* in gs://bucket/path/to/object.txt, the name of the object would be: 'object.txt'
*/
@property(nonatomic, readonly) NSString *name;
#pragma mark - Path Operations
/**
* Creates a new FIRStorageReference pointing to the root object.
* @return A new FIRStorageReference pointing to the root object.
*/
- (FIRStorageReference *)root;
/**
* Creates a new FIRStorageReference pointing to the parent of the current reference
* or nil if this instance references the root location.
* For example:
* path = foo/bar/baz parent = foo/bar
* path = foo parent = (root)
* path = (root) parent = nil
* @return A new FIRStorageReference pointing to the parent of the current reference.
*/
- (nullable FIRStorageReference *)parent;
/**
* Creates a new FIRStorageReference pointing to a child object of the current reference.
* path = foo child = bar newPath = foo/bar
* path = foo/bar child = baz newPath = foo/bar/baz
* All leading and trailing slashes will be removed, and consecutive slashes will be
* compressed to single slashes. For example:
* child = /foo/bar newPath = foo/bar
* child = foo/bar/ newPath = foo/bar
* child = foo///bar newPath = foo/bar
* @param path Path to append to the current path.
* @return A new FIRStorageReference pointing to a child location of the current reference.
*/
- (FIRStorageReference *)child:(NSString *)path;
#pragma mark - Uploads
/**
* Asynchronously uploads data to the currently specified FIRStorageReference,
* without additional metadata.
* This is not recommended for large files, and one should instead upload a file from disk.
* @param uploadData The NSData to upload.
* @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload.
*/
- (FIRStorageUploadTask *)putData:(NSData *)uploadData NS_SWIFT_NAME(putData(_:));
/**
* Asynchronously uploads data to the currently specified FIRStorageReference.
* This is not recommended for large files, and one should instead upload a file from disk.
* @param uploadData The NSData to upload.
* @param metadata FIRStorageMetadata containing additional information (MIME type, etc.)
* about the object being uploaded.
* @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload.
*/
// clang-format off
- (FIRStorageUploadTask *)putData:(NSData *)uploadData
metadata:(nullable FIRStorageMetadata *)metadata
NS_SWIFT_NAME(putData(_:metadata:));
// clang-format on
/**
* Asynchronously uploads data to the currently specified FIRStorageReference.
* This is not recommended for large files, and one should instead upload a file from disk.
* @param uploadData The NSData to upload.
* @param metadata FIRStorageMetadata containing additional information (MIME type, etc.)
* about the object being uploaded.
* @param completion A completion block that either returns the object metadata on success,
* or an error on failure.
* @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload.
*/
// clang-format off
- (FIRStorageUploadTask *)putData:(NSData *)uploadData
metadata:(nullable FIRStorageMetadata *)metadata
completion:(nullable void (^)(FIRStorageMetadata *_Nullable metadata,
NSError *_Nullable error))completion
NS_SWIFT_NAME(putData(_:metadata:completion:));
// clang-format on
/**
* Asynchronously uploads a file to the currently specified FIRStorageReference,
* without additional metadata.
* @param fileURL A URL representing the system file path of the object to be uploaded.
* @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload.
*/
- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL NS_SWIFT_NAME(putFile(from:));
/**
* Asynchronously uploads a file to the currently specified FIRStorageReference.
* @param fileURL A URL representing the system file path of the object to be uploaded.
* @param metadata FIRStorageMetadata containing additional information (MIME type, etc.)
* about the object being uploaded.
* @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload.
*/
// clang-format off
- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
metadata:(nullable FIRStorageMetadata *)metadata
NS_SWIFT_NAME(putFile(from:metadata:));
// clang-format on
/**
* Asynchronously uploads a file to the currently specified FIRStorageReference.
* @param fileURL A URL representing the system file path of the object to be uploaded.
* @param metadata FIRStorageMetadata containing additional information (MIME type, etc.)
* about the object being uploaded.
* @param completion A completion block that either returns the object metadata on success,
* or an error on failure.
* @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload.
*/
// clang-format off
- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
metadata:(nullable FIRStorageMetadata *)metadata
completion:(nullable void (^)(FIRStorageMetadata *_Nullable metadata,
NSError *_Nullable error))completion
NS_SWIFT_NAME(putFile(from:metadata:completion:));
// clang-format on
#pragma mark - Downloads
/**
* Asynchronously downloads the object at the FIRStorageReference to an NSData object in memory.
* An NSData of the provided max size will be allocated, so ensure that the device has enough free
* memory to complete the download. For downloading large files, writeToFile may be a better option.
* @param size The maximum size in bytes to download. If the download exceeds this size,
* the task will be cancelled and an error will be returned.
* @param completion A completion block that either returns the object data on success,
* or an error on failure.
* @return An FIRStorageDownloadTask that can be used to monitor or manage the download.
*/
// clang-format off
- (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size
completion:(void (^)(NSData *_Nullable data,
NSError *_Nullable error))completion
NS_SWIFT_NAME(getData(maxSize:completion:));
// clang-format on
/**
* Asynchronously retrieves a long lived download URL with a revokable token.
* This can be used to share the file with others, but can be revoked by a developer
* in the Firebase Console.
* @param completion A completion block that either returns the URL on success,
* or an error on failure.
*/
- (void)downloadURLWithCompletion:(void (^)(NSURL *_Nullable URL,
NSError *_Nullable error))completion;
/**
* Asynchronously downloads the object at the current path to a specified system filepath.
* @param fileURL A file system URL representing the path the object should be downloaded to.
* @return An FIRStorageDownloadTask that can be used to monitor or manage the download.
*/
- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL;
/**
* Asynchronously downloads the object at the current path to a specified system filepath.
* @param fileURL A file system URL representing the path the object should be downloaded to.
* @param completion A completion block that fires when the file download completes.
* Returns an NSURL pointing to the file path of the downloaded file on success,
* or an error on failure.
* @return An FIRStorageDownloadTask that can be used to monitor or manage the download.
*/
- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL
completion:(nullable void (^)(NSURL *_Nullable URL,
NSError *_Nullable error))completion;
#pragma mark - List Support
/**
* List all items (files) and prefixes (folders) under this StorageReference.
*
* This is a helper method for calling list() repeatedly until there are no more results.
* Consistency of the result is not guaranteed if objects are inserted or removed while this
* operation is executing. All results are buffered in memory.
*
* `listAll(completion:)` is only available for projects using Firebase Rules Version 2.
*
* @param completion A completion handler that will be invoked with all items and prefixes under
* the current StorageReference.
*/
- (void)listAllWithCompletion:(void (^)(FIRStorageListResult *result,
NSError *_Nullable error))completion;
/**
* List up to `maxResults` items (files) and prefixes (folders) under this StorageReference.
*
* "/" is treated as a path delimiter. Firebase Storage does not support unsupported object
* paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
* filtered.
*
* `list(maxResults:completion:)` is only available for projects using Firebase Rules Version 2.
*
* @param maxResults The maximum number of results to return in a single page. Must be greater
* than 0 and at most 1000.
* @param completion A completion handler that will be invoked with up to maxResults items and
* prefixes under the current StorageReference.
*/
- (void)listWithMaxResults:(int64_t)maxResults
completion:
(void (^)(FIRStorageListResult *result, NSError *_Nullable error))completion
NS_SWIFT_NAME(list(maxResults:completion:));
/**
* Resumes a previous call to list(maxResults:completion:)`, starting after a pagination token.
* Returns the next set of items (files) and prefixes (folders) under this StorageReference.
*
* "/" is treated as a path delimiter. Firebase Storage does not support unsupported object
* paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
* filtered.
*
* `list(maxResults:pageToken:completion:)`is only available for projects using Firebase Rules
* Version 2.
*
* @param maxResults The maximum number of results to return in a single page. Must be greater
* than 0 and at most 1000.
* @param pageToken A page token from a previous call to list.
* @param completion A completion handler that will be invoked with the next items and prefixes
* under the current StorageReference.
*/
- (void)listWithMaxResults:(int64_t)maxResults
pageToken:(NSString *)pageToken
completion:
(void (^)(FIRStorageListResult *result, NSError *_Nullable error))completion
NS_SWIFT_NAME(list(maxResults:pageToken:completion:));
#pragma mark - Metadata Operations
/**
* Retrieves metadata associated with an object at the current path.
* @param completion A completion block which returns the object metadata on success,
* or an error on failure.
*/
- (void)metadataWithCompletion:
(void (^)(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error))completion
NS_SWIFT_NAME(getMetadata(completion:));
/**
* Updates the metadata associated with an object at the current path.
* @param metadata An FIRStorageMetadata object with the metadata to update.
* @param completion A completion block which returns the FIRStorageMetadata on success,
* or an error on failure.
*/
// clang-format off
- (void)updateMetadata:(FIRStorageMetadata *)metadata
completion:(nullable void (^)(FIRStorageMetadata *_Nullable metadata,
NSError *_Nullable error))completion
NS_SWIFT_NAME(updateMetadata(_:completion:));
// clang-format on
#pragma mark - Delete
/**
* Deletes the object at the current path.
* @param completion A completion block which returns nil on success, or an error on failure.
*/
- (void)deleteWithCompletion:(nullable void (^)(NSError *_Nullable error))completion;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,75 @@
/*
* 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 "FIRStorageConstants.h"
#import "FIRStorageMetadata.h"
NS_ASSUME_NONNULL_BEGIN
/**
* A superclass to all FIRStorage*Tasks, including FIRStorageUploadTask
* and FIRStorageDownloadTask, to provide state transitions, event raising, and common storage
* or metadata and errors.
* Callbacks are always fired on the developer specified callback queue.
* If no queue is specified by the developer, it defaults to the main queue.
* Currently not thread safe, so only call methods on the main thread.
*/
NS_SWIFT_NAME(StorageTask)
@interface FIRStorageTask : NSObject
/**
* An immutable view of the task and associated metadata, progress, error, etc.
*/
@property(strong, readonly, nonatomic, nonnull) FIRStorageTaskSnapshot *snapshot;
@end
/**
* Defines task operations such as pause, resume, cancel, and enqueue for all tasks.
* All tasks are required to implement enqueue, which begins the task, and may optionally
* implement pause, resume, and cancel, which operate on the task to pause, resume, and cancel
* operations.
*/
NS_SWIFT_NAME(StorageTaskManagement)
@protocol FIRStorageTaskManagement <NSObject>
@required
/**
* Prepares a task and begins execution.
*/
- (void)enqueue;
@optional
/**
* Pauses a task currently in progress.
*/
- (void)pause;
/**
* Cancels a task currently in progress.
*/
- (void)cancel;
/**
* Resumes a task that is paused.
*/
- (void)resume;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,67 @@
/*
* 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 "FIRStorageConstants.h"
NS_ASSUME_NONNULL_BEGIN
@class FIRStorageMetadata;
@class FIRStorageReference;
@class FIRStorageTask;
/**
* FIRStorageTaskSnapshot represents an immutable view of a task.
* A Snapshot contains a task, storage reference, metadata (if it exists),
* progress, and an error (if one occurred).
*/
NS_SWIFT_NAME(StorageTaskSnapshot)
@interface FIRStorageTaskSnapshot : NSObject
/**
* Subclass of FIRStorageTask this snapshot represents.
*/
@property(readonly, copy, nonatomic) __kindof FIRStorageTask *task;
/**
* Metadata returned by the task, or nil if no metadata returned.
*/
@property(readonly, copy, nonatomic, nullable) FIRStorageMetadata *metadata;
/**
* FIRStorageReference this task is operates on.
*/
@property(readonly, copy, nonatomic) FIRStorageReference *reference;
/**
* NSProgress object which tracks the progress of an upload or download.
*/
@property(readonly, strong, nonatomic, nullable) NSProgress *progress;
/**
* Error during task execution, or nil if no error occurred.
*/
@property(readonly, copy, nonatomic, nullable) NSError *error;
/**
* Status of the task.
*/
@property(readonly, nonatomic) FIRStorageTaskStatus status;
@end
NS_ASSUME_NONNULL_END
@@ -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>
#import "FIRStorageObservableTask.h"
NS_ASSUME_NONNULL_BEGIN
/**
* FIRStorageUploadTask implements resumable uploads to a file in Firebase Storage.
* Uploads can be returned on completion with a completion callback, and can be monitored
* by attaching observers, or controlled by calling FIRStorageTask#pause, FIRStorageTask#resume,
* or FIRStorageTask#cancel.
* Uploads can take NSData in memory, or an NSURL to a file on disk.
* Uploads are performed on a background queue, and callbacks are raised on the developer
* specified callbackQueue in FIRStorage, or the main queue if left unspecified.
* Currently all uploads must be initiated and managed on the main queue.
*/
NS_SWIFT_NAME(StorageUploadTask)
@interface FIRStorageUploadTask : FIRStorageObservableTask <FIRStorageTaskManagement>
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,26 @@
/*
* 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 "FIRStorage.h"
#import "FIRStorageConstants.h"
#import "FIRStorageDownloadTask.h"
#import "FIRStorageListResult.h"
#import "FIRStorageMetadata.h"
#import "FIRStorageObservableTask.h"
#import "FIRStorageReference.h"
#import "FIRStorageTask.h"
#import "FIRStorageTaskSnapshot.h"
#import "FIRStorageUploadTask.h"
@@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef FIRAuthInterop_h
#define FIRAuthInterop_h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/** @typedef FIRTokenCallback
@brief The type of block which gets called when a token is ready.
*/
typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error)
NS_SWIFT_NAME(TokenCallback);
/// Common methods for Auth interoperability.
NS_SWIFT_NAME(AuthInterop)
@protocol FIRAuthInterop
/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback;
/// Get the current Auth user's UID. Returns nil if there is no user signed in.
- (nullable NSString *)getUserID;
@end
NS_ASSUME_NONNULL_END
#endif /* FIRAuthInterop_h */
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+319
View File
@@ -0,0 +1,319 @@
[![Version](https://img.shields.io/cocoapods/v/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
[![License](https://img.shields.io/cocoapods/l/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
[![Actions Status][gh-abtesting-badge]][gh-actions]
[![Actions Status][gh-appcheck-badge]][gh-actions]
[![Actions Status][gh-appdistribution-badge]][gh-actions]
[![Actions Status][gh-auth-badge]][gh-actions]
[![Actions Status][gh-cocoapods-integration-badge]][gh-actions]
[![Actions Status][gh-core-badge]][gh-actions]
[![Actions Status][gh-core-diagnostics-badge]][gh-actions]
[![Actions Status][gh-crashlytics-badge]][gh-actions]
[![Actions Status][gh-database-badge]][gh-actions]
[![Actions Status][gh-datatransport-badge]][gh-actions]
[![Actions Status][gh-dynamiclinks-badge]][gh-actions]
[![Actions Status][gh-firebasepod-badge]][gh-actions]
[![Actions Status][gh-firestore-badge]][gh-actions]
[![Actions Status][gh-functions-badge]][gh-actions]
[![Actions Status][gh-google-utilities-badge]][gh-actions]
[![Actions Status][gh-google-utilities-components-badge]][gh-actions]
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
[![Actions Status][gh-interop-badge]][gh-actions]
[![Actions Status][gh-messaging-badge]][gh-actions]
[![Actions Status][gh-mlmodeldownloader-badge]][gh-actions]
[![Actions Status][gh-performance-badge]][gh-actions]
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
[![Actions Status][gh-storage-badge]][gh-actions]
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
[![Actions Status][gh-zip-badge]][gh-actions]
# Firebase Apple Open Source Development
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
and FirebaseML.
Firebase is an app development platform with tools to help you build, grow and
monetize your app. More information about Firebase can be found on the
[official Firebase website](https://firebase.google.com).
## Installation
See the subsections below for details about the different installation methods.
1. [Standard pod install](#standard-pod-install)
1. [Swift Package Manager](#swift-package-manager)
1. [Installing from the GitHub repo](#installing-from-github)
1. [Experimental Carthage](#carthage-ios-only)
### Standard pod install
Go to
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
### Swift Package Manager
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file.
### Installing from GitHub
These instructions can be used to access the Firebase repo at other branches,
tags, or commits.
#### Background
See
[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod)
for instructions and options about overriding pod source locations.
#### Accessing Firebase Source Snapshots
All of the official releases are tagged in this repo and available via CocoaPods. To access a local
source snapshot or unreleased branch, use Podfile directives like the following:
To access FirebaseFirestore via a branch:
```ruby
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
```
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
```ruby
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
```
### Carthage (iOS only)
Instructions for the experimental Carthage distribution are at
[Carthage](Carthage.md).
### Using Firebase from a Framework or a library
[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md)
## Development
To develop Firebase software in this repository, ensure that you have at least
the following software:
* Xcode 12.2 (or later)
CocoaPods is still the canonical way to develop, but much of the repo now supports
development with Swift Package Manager.
### CocoaPods
Install
* CocoaPods 1.10.0 (or later)
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
For the pod that you want to develop:
```ruby
pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios
```
Note: If the CocoaPods cache is out of date, you may need to run
`pod repo update` before the `pod gen` command.
Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
those platforms. Since 10.2, Xcode does not properly handle multi-platform
CocoaPods workspaces.
Firestore has a self contained Xcode project. See
[Firestore/README](Firestore/README.md) Markdown file.
#### Development for Catalyst
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
* Check the Mac box in the App-iOS Build Settings
* Sign the App in the Settings Signing & Capabilities tab
* Click Pods in the Project Manager
* Add Signing to the iOS host app and unit test targets
* Select the Unit-unit scheme
* Run it to build and test
Alternatively disable signing in each target:
* Go to Build Settings tab
* Click `+`
* Select `Add User-Defined Setting`
* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO`
### Swift Package Manager
* To enable test schemes: `./scripts/setup_spm_tests.sh`
* `open Package.swift` or double click `Package.swift` in Finder.
* Xcode will open the project
* Choose a scheme for a library to build or test suite to run
* Choose a target platform by selecting the run destination along with the scheme
### Adding a New Firebase Pod
See [AddNewPod](AddNewPod.md) Markdown file.
### Managing Headers and Imports
See [HeadersImports](HeadersImports.md) Markdown file.
### Code Formatting
To ensure that the code is formatted consistently, run the script
[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh)
before creating a PR.
GitHub Actions will verify that any code changes are done in a style compliant
way. Install `clang-format` and `mint`:
```console
brew install clang-format@13
brew install mint
```
### Running Unit Tests
Select a scheme and press Command-u to build a component and run its unit tests.
### Running Sample Apps
In order to run the sample apps and integration tests, you'll need a valid
`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist
files without real values, but can be replaced with real plist files. To get your own
`GoogleService-Info.plist` files:
1. Go to the [Firebase Console](https://console.firebase.google.com/)
2. Create a new Firebase project, if you don't already have one
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
identifier (e.g. `com.google.Database-Example`)
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
### Coverage Report Generation
See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file.
## Specific Component Instructions
See the sections below for any special instructions for those components.
### Firebase Auth
If you're doing specific Firebase Auth development, see
[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about
building and running the FirebaseAuth pod along with various samples and tests.
### Firebase Database
The Firebase Database Integration tests can be run against a locally running Database Emulator
or against a production instance.
To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before
running the integration test.
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
running.
### Firebase Performance Monitoring
If you're doing specific Firebase Performance Monitoring development, see
[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK
and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about
integrating Performance with the dev test App.
### Firebase Storage
To run the Storage Integration tests, follow the instructions in
[FIRStorageIntegrationTests.m](FirebaseStorage/Tests/Integration/FIRStorageIntegrationTests.m).
#### Push Notifications
Push notifications can only be delivered to specially provisioned App IDs in the developer portal.
In order to actually test receiving push notifications, you will need to:
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
account, and enable that App ID for push notifications.
2. You'll also need to
[upload your APNs Provider Authentication Key or certificate to the
Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
#### iOS Simulator
The iOS Simulator cannot register for remote notifications, and will not receive push notifications.
In order to receive push notifications, you'll have to follow the steps above and run the app on a
physical device.
## Building with Firebase on Apple platforms
Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues
to be community supported. Thanks to community contributions for many of the multi-platform PRs.
At this time, most of Firebase's products are available across Apple platforms. There are still
a few gaps, especially on watchOS. For details about the current support matrix, see
[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform)
in Firebase's documentation.
### watchOS
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and
work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample).
Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit
test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected
on watchOS. If you encounter this, please
[file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
During app setup in the console, you may get to a step that mentions something like "Checking if the
app has communicated with our servers". This relies on Analytics and will not work on watchOS.
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
#### Additional Crashlytics Notes
* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are
not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded)
## Combine
Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine
framework. This module is currently under development, and not yet supported for use in production
environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md).
## Roadmap
See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source
plans and directions.
## Contributing
See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase
Apple SDK.
## License
The contents of this repository are licensed under the
[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
Your use of Firebase is governed by the
[Terms of Service for Firebase Services](https://firebase.google.com/terms/).
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
[gh-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg
[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/badge.svg
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
[gh-dynamiclinks-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/dynamiclinks/badge.svg
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg
[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/badge.svg
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
[gh-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg
[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/badge.svg
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
[gh-zip-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/zip/badge.svg