diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index 71593ef537..6f6d0e8e8b 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -30,8 +30,7 @@ jobs: runs-on: macos-11 strategy: matrix: - # TODO: The --skip-tests might be removable with Xcode 13.2+ - target: [ios, tvos, macos --skip-tests, watchos] + target: [ios, tvos, macos, watchos] steps: - uses: actions/checkout@v2 - name: Setup Bundler diff --git a/CoreOnly/Sources/Firebase.h b/CoreOnly/Sources/Firebase.h index 4dd615c6ec..8a7420d42c 100755 --- a/CoreOnly/Sources/Firebase.h +++ b/CoreOnly/Sources/Firebase.h @@ -51,7 +51,7 @@ #endif #if __has_include("FirebaseFunctions-umbrella.h") -@import FirebaseFunctions; + #import #endif #if __has_include() @@ -75,7 +75,7 @@ #endif #if __has_include("FirebaseStorage-umbrella.h") -@import FirebaseStorage; + #import #endif #endif // defined(__has_include) diff --git a/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift b/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift index 31e3ecd759..066520610c 100644 --- a/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift +++ b/CoreOnly/Tests/FirebasePodTest/FirebasePodTest/AppDelegate.swift @@ -18,7 +18,6 @@ import Firebase import FirebaseAnalyticsSwift import FirebaseFirestoreSwift import FirebaseInAppMessagingSwift -import FirebaseStorage class CoreExists: FirebaseApp {} class AnalyticsExists: Analytics {} diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index 5736176d67..582174df70 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -3,6 +3,18 @@ - [added] The zip and Carthage distibutions now include the Swift extension frameworks. (#7819) - [changed] **Breaking change**: Update the minimum supported versions for the zip and Carthage distributions to iOS 11.0, tvOS 11.0 and macOS 10.13. (#9633) +- [changed] **Breaking change**: CocoaPods Podfiles must include `use_frameworks!` or + `use_frameworks! :linkage => :static`. +- [deprecated] Usage of the Firebase pod, the Firebase module (`import Firebase`), and `Firebase.h` + is deprecated. Use the specific Firebase product instead like: `pod 'FirebaseMessaging'` and + `import FirebaseMessaging`. +- [changed] For Swift Package Manager installations, `import Firebase` will no longer implicitly + import Firebase Storage and Firebase Functions APIs. Use `import FirebaseStorage` and + `import FirebaseFunctions`. +- [changed] C++/Objective C++ clients should use `#import ` + and `#import ` to access Functions and Storage APIs, + respectively. C++/Objective C++ clients using Swift Package Manager should find alternative + workarounds at https://forums.swift.org/t/importing-swift-libraries-from-objective-c/56730. # Firebase 8.10.0 - [fixed] Fixed platform availability checks in Swift Package Manager that may prevent code diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index 61d484118f..1bee530ed1 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -45,6 +45,17 @@ Cloud Functions for Firebase. s.dependency 'FirebaseSharedSwift', '~> 9.0' s.dependency 'GTMSessionFetcher/Core', '~> 1.5' + s.test_spec 'objc' do |objc_tests| + objc_tests.platforms = { + :ios => ios_deployment_target, + :osx => '10.15', + :tvos => tvos_deployment_target + } + objc_tests.source_files = [ + 'FirebaseFunctions/Tests/ObjCIntegration/ObjC*' + ] + end + s.test_spec 'integration' do |int_tests| int_tests.platforms = { :ios => ios_deployment_target, diff --git a/FirebaseFunctions/Tests/ObjCIntegration/ObjCAPITests.m b/FirebaseFunctions/Tests/ObjCIntegration/ObjCAPITests.m index d431158b9a..f6df090236 100644 --- a/FirebaseFunctions/Tests/ObjCIntegration/ObjCAPITests.m +++ b/FirebaseFunctions/Tests/ObjCIntegration/ObjCAPITests.m @@ -35,7 +35,7 @@ FIRHTTPSCallable *callable = [func HTTPSCallableWithName:@"name"]; - [func useEmulatorWithHost:@"host" port:@"port"]; + [func useEmulatorWithHost:@"host" port:123]; #pragma mark - HTTPSCallable and HTTPSCallableResult [callable @@ -73,5 +73,6 @@ case FIRFunctionsErrorCodeUnauthenticated: return error.code; } + return error.code; } @end diff --git a/FirebaseFunctions/Tests/ObjCIntegration/ObjCPPAPITests.mm b/FirebaseFunctions/Tests/ObjCIntegration/ObjCPPAPITests.mm new file mode 100644 index 0000000000..f5c78711d5 --- /dev/null +++ b/FirebaseFunctions/Tests/ObjCIntegration/ObjCPPAPITests.mm @@ -0,0 +1,78 @@ +// Copyright 2022 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 + +#import +#import "FirebaseCore/FirebaseCore.h" + +@interface ObjCPPAPICoverage : XCTestCase +@end + +@implementation ObjCPPAPICoverage + +- (void)apis { +#pragma mark - Functions + + FIRApp *app = [FIRApp defaultApp]; + FIRFunctions *func = [FIRFunctions functions]; + func = [FIRFunctions functionsForApp:app]; + func = [FIRFunctions functionsForRegion:@"my-region"]; + func = [FIRFunctions functionsForCustomDomain:@"my-domain"]; + func = [FIRFunctions functionsForApp:app region:@"my-region"]; + func = [FIRFunctions functionsForApp:app customDomain:@"my-domain"]; + + FIRHTTPSCallable *callable = [func HTTPSCallableWithName:@"name"]; + + [func useEmulatorWithHost:@"host" port:123]; + +#pragma mark - HTTPSCallable and HTTPSCallableResult + [callable + callWithCompletion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) { + __unused id data = result.data; + }]; + [callable callWithObject:nil + completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) { + [result data]; + }]; + callable.timeoutInterval = 60; + [callable timeoutInterval]; +} + +#pragma mark - FunctionsError + +- (FIRFunctionsErrorCode)errorCodes:(NSError *)error { + switch (error.code) { + case FIRFunctionsErrorCodeOK: + case FIRFunctionsErrorCodeCancelled: + case FIRFunctionsErrorCodeUnknown: + case FIRFunctionsErrorCodeInvalidArgument: + case FIRFunctionsErrorCodeDeadlineExceeded: + case FIRFunctionsErrorCodeNotFound: + case FIRFunctionsErrorCodeAlreadyExists: + case FIRFunctionsErrorCodePermissionDenied: + case FIRFunctionsErrorCodeResourceExhausted: + case FIRFunctionsErrorCodeFailedPrecondition: + case FIRFunctionsErrorCodeAborted: + case FIRFunctionsErrorCodeOutOfRange: + case FIRFunctionsErrorCodeUnimplemented: + case FIRFunctionsErrorCodeInternal: + case FIRFunctionsErrorCodeUnavailable: + case FIRFunctionsErrorCodeDataLoss: + case FIRFunctionsErrorCodeUnauthenticated: + return (FIRFunctionsErrorCode)error.code; + } + return (FIRFunctionsErrorCode)error.code; +} +@end diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index 80e95e557d..da62dabb04 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -54,7 +54,7 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas } objc_tests.source_files = [ 'FirebaseStorageInternal/Tests/Integration/*.[mh]', - 'FirebaseStorage/Tests/ObjCIntegration/*.m', + 'FirebaseStorage/Tests/ObjCIntegration/*.{m,mm}', ] objc_tests.requires_app_host = true objc_tests.resources = 'FirebaseStorageInternal/Tests/Integration/Resources/1mb.dat', diff --git a/FirebaseStorage/Tests/ObjCIntegration/ObjCAPITests.m b/FirebaseStorage/Tests/ObjCIntegration/ObjCAPITests.m index a6c01adf15..e1c46ebc6f 100644 --- a/FirebaseStorage/Tests/ObjCIntegration/ObjCAPITests.m +++ b/FirebaseStorage/Tests/ObjCIntegration/ObjCAPITests.m @@ -115,12 +115,6 @@ } #endif -#ifdef Firebase9Breaking -- (NSString *)FIRStorageConstantsGlobal { - return FIRStorageErrorDomain; -} -#endif - - (void)FIRStorageListResultApis:(FIRStorageListResult *)result { NSArray __unused *prefixes = [result prefixes]; NSArray __unused *items = [result items]; diff --git a/FirebaseStorage/Tests/ObjCIntegration/ObjCPPAPITests.mm b/FirebaseStorage/Tests/ObjCIntegration/ObjCPPAPITests.mm new file mode 100644 index 0000000000..8995fa888a --- /dev/null +++ b/FirebaseStorage/Tests/ObjCIntegration/ObjCPPAPITests.mm @@ -0,0 +1,218 @@ +// Copyright 2022 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 + +#import "FirebaseCore/FirebaseCore.h" +#import "FirebaseStorage/FIRStorageTypedefs.h" +#import "FirebaseStorage/FirebaseStorage-Swift.h" + +@interface ObjCPPAPICoverage : XCTestCase +@end + +@implementation ObjCPPAPICoverage + +- (void)FIRStorageApis { + FIRApp *app = [FIRApp defaultApp]; + FIRStorage *storage = [FIRStorage storage]; + storage = [FIRStorage storageForApp:app]; + storage = [FIRStorage storageWithURL:@"my-url"]; + storage = [FIRStorage storageForApp:app URL:@"my-url"]; + app = [storage app]; + app = storage.app; + [storage setMaxUploadRetryTime:[storage maxUploadRetryTime]]; + storage.maxUploadRetryTime = storage.maxUploadRetryTime + 1; + [storage setMaxDownloadRetryTime:[storage maxDownloadRetryTime]]; + storage.maxDownloadRetryTime = storage.maxDownloadRetryTime + 1; + [storage setMaxOperationRetryTime:[storage maxOperationRetryTime]]; + [storage setCallbackQueue:[storage callbackQueue]]; + FIRStorageReference *ref = [storage reference]; + ref = [storage referenceForURL:@"my-url"]; + ref = [storage referenceWithPath:@"my-path"]; + [storage useEmulatorWithHost:@"my-host" port:123]; +} + +- (void)FIRStorageReferenceApis { + FIRStorageReference *ref = [[FIRStorage storage] reference]; + [ref storage]; + [ref bucket]; + [ref fullPath]; + [ref name]; + + ref = [ref root]; + ref = [ref parent]; + ref = [ref child:@"path"]; + + NSData *data = [NSData data]; + FIRStorageUploadTask *task = [ref putData:data]; + task = [ref putData:data metadata:nil]; + task = [ref putData:data + metadata:nil + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error){ + }]; + + NSURL *file = [NSURL URLWithString:@"my-url"]; + task = [ref putFile:file]; + task = [ref putFile:file metadata:nil]; + task = [ref putFile:file + metadata:nil + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error){ + }]; + + FIRStorageDownloadTask *task2 = + [ref dataWithMaxSize:123 + completion:^(NSData *_Nullable data, NSError *_Nullable error){ + }]; + + [ref downloadURLWithCompletion:^(NSURL *_Nullable URL, NSError *_Nullable error){ + }]; + + task2 = [ref writeToFile:file]; + task2 = [ref writeToFile:file + completion:^(NSURL *_Nullable URL, NSError *_Nullable error){ + }]; + + [ref listAllWithCompletion:^(FIRStorageListResult *_Nonnull result, NSError *_Nullable error){ + }]; + + [ref listWithMaxResults:123 + completion:^(FIRStorageListResult *_Nonnull result, NSError *_Nullable error){ + }]; + [ref listWithMaxResults:123 + pageToken:@"my token" + completion:^(FIRStorageListResult *_Nonnull result, NSError *_Nullable error){ + }]; + + [ref metadataWithCompletion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { + [ref updateMetadata:metadata + completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error){ + }]; + }]; + + [ref deleteWithCompletion:^(NSError *_Nullable error){ + }]; +} + +#ifdef COCOAPODS +- (void)FIRStorageConstantsTypedefs { + FIRStorageHandle __unused handle; + FIRStorageVoidDataError __unused funcPtr1; + FIRStorageVoidError __unused funcPtr2; + FIRStorageVoidMetadata __unused funcPtr3; + FIRStorageVoidMetadataError __unused funcPtr4; + FIRStorageVoidSnapshot __unused funcPtr5; + FIRStorageVoidURLError __unused funcPtr6; +} +#endif + +- (void)FIRStorageListResultApis:(FIRStorageListResult *)result { + NSArray __unused *prefixes = [result prefixes]; + NSArray __unused *items = [result items]; + NSString __unused *token = [result pageToken]; +} + +- (FIRStorageTaskStatus)taskStatuses:(FIRStorageTaskStatus)status { + switch (status) { + case FIRStorageTaskStatusUnknown: + case FIRStorageTaskStatusResume: + case FIRStorageTaskStatusProgress: + case FIRStorageTaskStatusPause: + case FIRStorageTaskStatusSuccess: + case FIRStorageTaskStatusFailure: + return status; + } +} + +- (FIRStorageErrorCode)errorCodes:(NSError *)error { + switch (error.code) { + case FIRStorageErrorCodeUnknown: + case FIRStorageErrorCodeObjectNotFound: + case FIRStorageErrorCodeBucketNotFound: + case FIRStorageErrorCodeProjectNotFound: + case FIRStorageErrorCodeQuotaExceeded: + case FIRStorageErrorCodeUnauthenticated: + case FIRStorageErrorCodeUnauthorized: + case FIRStorageErrorCodeRetryLimitExceeded: + case FIRStorageErrorCodeNonMatchingChecksum: + case FIRStorageErrorCodeDownloadSizeExceeded: + case FIRStorageErrorCodeCancelled: + case FIRStorageErrorCodeInvalidArgument: + return (FIRStorageErrorCode)error.code; + } + // The cast is not needed in plain Objective C. + return (FIRStorageErrorCode)error.code; +} + +- (void)FIRStorageMetadataApis { + FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:@{}]; + [metadata bucket]; + [metadata setCacheControl:[metadata cacheControl]]; + [metadata setContentDisposition:[metadata contentDisposition]]; + [metadata setContentEncoding:[metadata contentEncoding]]; + [metadata setContentLanguage:[metadata contentLanguage]]; + [metadata setContentType:[metadata contentType]]; + [metadata md5Hash]; + [metadata generation]; + [metadata setCustomMetadata:[metadata customMetadata]]; + [metadata metageneration]; + [metadata name]; + [metadata path]; + [metadata size]; + [metadata timeCreated]; + [metadata updated]; + [metadata storageReference]; + FIRStorageMetadata __unused *ref2 = [metadata initWithDictionary:@{}]; + NSDictionary __unused *dict = [metadata dictionaryRepresentation]; + [metadata isFile]; + [metadata isFolder]; +} + +- (void)FIRStorageObservableTaskApis { + FIRStorageReference *ref = [[FIRStorage storage] reference]; + FIRStorageObservableTask *task = [ref writeToFile:[NSURL URLWithString:@"my-url"]]; + + NSString __unused *handle = [task observeStatus:FIRStorageTaskStatusPause + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot){ + }]; + + [task removeObserverWithHandle:@"handle"]; + + [task removeAllObserversForStatus:FIRStorageTaskStatusUnknown]; + + [task removeAllObservers]; +} + +- (void)FIRStorageTaskApis { + FIRStorageReference *ref = [[FIRStorage storage] reference]; + FIRStorageTask *task = [ref writeToFile:[NSURL URLWithString:@"my-url"]]; + [task snapshot]; +} + +- (void)FIRStorageTaskManagementApis:(id)task { + [task enqueue]; + [task pause]; + [task cancel]; + [task resume]; +} + +- (void)FIRStorageTaskSnaphotApis:(FIRStorageTaskSnapshot *)snapshot { + [snapshot task]; + [snapshot metadata]; + [snapshot reference]; + [snapshot progress]; + [snapshot error]; + [snapshot status]; +} + +@end diff --git a/Package.swift b/Package.swift index d9f8d50704..8ffab9a2aa 100644 --- a/Package.swift +++ b/Package.swift @@ -767,6 +767,10 @@ let package = Package( dependencies: ["FirebaseFunctions", "SharedTestUtilities"], path: "FirebaseFunctions/Tests/ObjCIntegration", + // See https://forums.swift.org/t/importing-swift-libraries-from-objective-c/56730 + exclude: [ + "ObjCPPAPITests.mm", + ], cSettings: [ .headerSearchPath("../../.."), ] @@ -1103,6 +1107,10 @@ let package = Package( name: "StorageObjcIntegration", dependencies: ["FirebaseStorage"], path: "FirebaseStorage/Tests/ObjcIntegration", + exclude: [ + // See https://forums.swift.org/t/importing-swift-libraries-from-objective-c/56730 + "ObjCPPAPITests.mm", + ], cSettings: [ .headerSearchPath("../../.."), ] diff --git a/scripts/check_imports.swift b/scripts/check_imports.swift index e66a9c0b32..6f6a1a21ab 100755 --- a/scripts/check_imports.swift +++ b/scripts/check_imports.swift @@ -29,7 +29,7 @@ let skipDirPatterns = ["/Sample/", "/Pods/", "FirebaseStorageInternal/Tests/Inte "FirebaseInAppMessaging/Tests/Integration/", "SymbolCollisionTest/", "/gen/", "CocoapodsIntegrationTest/", "FirebasePerformance/Tests/TestApp/", - "cmake-build-debug/", "build/", + "cmake-build-debug/", "build/", "ObjCIntegration/", "FirebasePerformance/Tests/FIRPerfE2E/"] + [ "CoreOnly/Sources", // Skip Firebase.h.