Skip to content

Commit

Permalink
feat(functions): Swift Package Manager support (#16770)
Browse files Browse the repository at this point in the history
  • Loading branch information
russellwheatley authored Nov 27, 2024
1 parent 849cf54 commit 548310f
Show file tree
Hide file tree
Showing 20 changed files with 262 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/all_plugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ jobs:
"flutter build web"
swift-integration:
runs-on: macos-latest
timeout-minutes: 30
timeout-minutes: 40
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/scripts/swift-integration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ void main() async {
await buildSwiftExampleApp('ios', 'cloud_firestore');
await buildSwiftExampleApp('macos', 'firebase_core');
await buildSwiftExampleApp('macos', 'cloud_firestore');
await buildSwiftExampleApp('ios', 'cloud_functions');
await buildSwiftExampleApp('macos', 'cloud_functions');
}

Future<void> deleteFirstLine(String filePath) async {
Expand Down
2 changes: 2 additions & 0 deletions packages/cloud_functions/cloud_functions/example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/

# IntelliJ related
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Pod::Spec.new do |s|
s.license = { :file => '../LICENSE' }
s.authors = 'The Chromium Authors'
s.source = { :path => '.' }
s.source_files = 'Classes/**/*.{h,m}'
s.public_header_files = 'Classes/*.h'
s.source_files = 'cloud_functions/Sources/cloud_functions/**/*.{h,m}'
s.public_header_files = 'cloud_functions/Sources/cloud_functions/include/*.h'
s.ios.deployment_target = '13.0'

# Flutter dependencies
Expand All @@ -37,7 +37,7 @@ Pod::Spec.new do |s|

s.static_framework = true
s.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\@\\\"#{library_version}\\\" LIBRARY_NAME=\\@\\\"flutter-fire-fn\\\"",
'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\\"#{library_version}\\\" LIBRARY_NAME=\\\"flutter-fire-fn\\\"",
'DEFINES_MODULE' => 'YES'
}
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

// Copyright 2024, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import Foundation
import PackageDescription

enum ConfigurationError: Error {
case fileNotFound(String)
case parsingError(String)
case invalidFormat(String)
}

let functionsDirectory = String(URL(string: #file)!.deletingLastPathComponent().absoluteString
.dropLast())

func loadFirebaseSDKVersion() throws -> String {
let firebaseCoreScriptPath = NSString.path(withComponents: [
functionsDirectory,
"..",
"generated_firebase_sdk_version.txt",
])
do {
let version = try String(contentsOfFile: firebaseCoreScriptPath, encoding: .utf8)
.trimmingCharacters(in: .whitespacesAndNewlines)
return version
} catch {
throw ConfigurationError
.fileNotFound("Error loading or parsing generated_firebase_sdk_version.txt: \(error)")
}
}

func loadPubspecVersions() throws -> (packageVersion: String, firebaseCoreVersion: String) {
let pubspecPath = NSString.path(withComponents: [functionsDirectory, "..", "..", "pubspec.yaml"])
do {
let yamlString = try String(contentsOfFile: pubspecPath, encoding: .utf8)
let lines = yamlString.split(separator: "\n")

guard let packageVersionLine = lines.first(where: { $0.starts(with: "version:") }) else {
throw ConfigurationError.invalidFormat("No package version line found in pubspec.yaml")
}
var packageVersion = packageVersionLine.split(separator: ":")[1]
.trimmingCharacters(in: .whitespaces)
.replacingOccurrences(of: "+", with: "-")
packageVersion = packageVersion.replacingOccurrences(of: "^", with: "")

guard let firebaseCoreVersionLine = lines.first(where: { $0.contains("firebase_core:") }) else {
throw ConfigurationError
.invalidFormat("No firebase_core dependency version line found in pubspec.yaml")
}
var firebaseCoreVersion = firebaseCoreVersionLine.split(separator: ":")[1]
.trimmingCharacters(in: .whitespaces)
firebaseCoreVersion = firebaseCoreVersion.replacingOccurrences(of: "^", with: "")

return (packageVersion, firebaseCoreVersion)
} catch {
throw ConfigurationError.fileNotFound("Error loading or parsing pubspec.yaml: \(error)")
}
}

let library_version: String
let firebase_sdk_version_string: String
let firebase_core_version_string: String
let shared_spm_tag = "-firebase-core-swift"

do {
library_version = try loadPubspecVersions().packageVersion
firebase_sdk_version_string = try loadFirebaseSDKVersion()
firebase_core_version_string = try loadPubspecVersions().firebaseCoreVersion
} catch {
fatalError("Failed to load configuration: \(error)")
}

guard let firebase_sdk_version = Version(firebase_sdk_version_string) else {
fatalError("Invalid Firebase SDK version: \(firebase_sdk_version_string)")
}

guard let shared_spm_version = Version("\(firebase_core_version_string)\(shared_spm_tag)") else {
fatalError("Invalid firebase_core version: \(firebase_core_version_string)\(shared_spm_tag)")
}

let package = Package(
name: "cloud_functions",
platforms: [
.iOS("13.0"),
],
products: [
.library(name: "cloud-functions", targets: ["cloud_functions"]),
],
dependencies: [
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: firebase_sdk_version),
.package(url: "https://github.com/firebase/flutterfire", exact: shared_spm_version),
],
targets: [
.target(
name: "cloud_functions",
dependencies: [
.product(name: "FirebaseFunctions", package: "firebase-ios-sdk"),
// Wrapper dependency
.product(name: "firebase-core-shared", package: "flutterfire"),
],
resources: [
.process("Resources"),
],
cSettings: [
.headerSearchPath("include"),
.define("LIBRARY_VERSION", to: "\"\(library_version)\""),
.define("LIBRARY_NAME", to: "\"flutter-fire-fn\""),
]
),
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "FLTFirebaseFunctionsPlugin.h"
#import "include/FLTFirebaseFunctionsPlugin.h"

@import FirebaseFunctions;
#if __has_include(<firebase_core/FLTFirebasePluginRegistry.h>)
#import <firebase_core/FLTFirebasePluginRegistry.h>
#else
#import <FLTFirebasePluginRegistry.h>
#endif

NSString *const kFLTFirebaseFunctionsChannelName = @"plugins.flutter.io/firebase_functions";

Expand Down Expand Up @@ -175,11 +179,11 @@ - (NSDictionary *_Nonnull)pluginConstantsForFIRApp:(FIRApp *)firebase_app {
}

- (NSString *_Nonnull)firebaseLibraryName {
return LIBRARY_NAME;
return @LIBRARY_NAME;
}

- (NSString *_Nonnull)firebaseLibraryVersion {
return LIBRARY_VERSION;
return @LIBRARY_VERSION;
}

- (NSString *_Nonnull)flutterChannelName {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <TargetConditionals.h>

#if TARGET_OS_OSX
#import <FlutterMacOS/FlutterMacOS.h>
Expand All @@ -9,7 +10,11 @@
#endif

#import <Foundation/Foundation.h>
#if __has_include(<firebase_core/FLTFirebasePlugin.h>)
#import <firebase_core/FLTFirebasePlugin.h>
#else
#import <FLTFirebasePlugin.h>
#endif

@interface FLTFirebaseFunctionsPlugin : FLTFirebasePlugin <FlutterPlugin, FLTFirebasePlugin>
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11.4.0

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ Pod::Spec.new do |s|
s.license = { :file => '../LICENSE' }
s.authors = 'The Chromium Authors'
s.source = { :path => '.' }
s.source_files = 'Classes/**/*.{h,m}'
s.public_header_files = 'Classes/*.h'
s.source_files = 'cloud_functions/Sources/cloud_functions/**/*.{h,m}'
s.public_header_files = 'cloud_functions/Sources/cloud_functions/include/*.h'
s.platform = :osx, '10.13'

# Flutter dependencies
Expand All @@ -55,7 +55,7 @@ Pod::Spec.new do |s|

s.static_framework = true
s.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\@\\\"#{library_version}\\\" LIBRARY_NAME=\\@\\\"flutter-fire-fn\\\"",
'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\\"#{library_version}\\\" LIBRARY_NAME=\\\"flutter-fire-fn\\\"",
'DEFINES_MODULE' => 'YES'
}
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

// Copyright 2024, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import Foundation
import PackageDescription

enum ConfigurationError: Error {
case fileNotFound(String)
case parsingError(String)
case invalidFormat(String)
}

let functionsDirectory = String(URL(string: #file)!.deletingLastPathComponent().absoluteString
.dropLast())

func loadFirebaseSDKVersion() throws -> String {
let firebaseCoreScriptPath = NSString.path(withComponents: [
functionsDirectory,
"..",
"..",
"ios",
"generated_firebase_sdk_version.txt",
])
do {
let version = try String(contentsOfFile: firebaseCoreScriptPath, encoding: .utf8)
.trimmingCharacters(in: .whitespacesAndNewlines)
return version
} catch {
throw ConfigurationError
.fileNotFound("Error loading or parsing generated_firebase_sdk_version.txt: \(error)")
}
}

func loadPubspecVersions() throws -> (packageVersion: String, firebaseCoreVersion: String) {
let pubspecPath = NSString.path(withComponents: [functionsDirectory, "..", "..", "pubspec.yaml"])
do {
let yamlString = try String(contentsOfFile: pubspecPath, encoding: .utf8)
let lines = yamlString.split(separator: "\n")

guard let packageVersionLine = lines.first(where: { $0.starts(with: "version:") }) else {
throw ConfigurationError.invalidFormat("No package version line found in pubspec.yaml")
}
var packageVersion = packageVersionLine.split(separator: ":")[1]
.trimmingCharacters(in: .whitespaces)
.replacingOccurrences(of: "+", with: "-")
packageVersion = packageVersion.replacingOccurrences(of: "^", with: "")

guard let firebaseCoreVersionLine = lines.first(where: { $0.contains("firebase_core:") }) else {
throw ConfigurationError
.invalidFormat("No firebase_core dependency version line found in pubspec.yaml")
}
var firebaseCoreVersion = firebaseCoreVersionLine.split(separator: ":")[1]
.trimmingCharacters(in: .whitespaces)
firebaseCoreVersion = firebaseCoreVersion.replacingOccurrences(of: "^", with: "")

return (packageVersion, firebaseCoreVersion)
} catch {
throw ConfigurationError.fileNotFound("Error loading or parsing pubspec.yaml: \(error)")
}
}

let library_version: String
let firebase_sdk_version_string: String
let firebase_core_version_string: String
let shared_spm_tag = "-firebase-core-swift"

do {
library_version = try loadPubspecVersions().packageVersion
firebase_sdk_version_string = try loadFirebaseSDKVersion()
firebase_core_version_string = try loadPubspecVersions().firebaseCoreVersion
} catch {
fatalError("Failed to load configuration: \(error)")
}

guard let firebase_sdk_version = Version(firebase_sdk_version_string) else {
fatalError("Invalid Firebase SDK version: \(firebase_sdk_version_string)")
}

guard let shared_spm_version = Version("\(firebase_core_version_string)\(shared_spm_tag)") else {
fatalError("Invalid firebase_core version: \(firebase_core_version_string)\(shared_spm_tag)")
}

let package = Package(
name: "cloud_functions",
platforms: [
.macOS("10.15"),
],
products: [
.library(name: "cloud-functions", targets: ["cloud_functions"]),
],
dependencies: [
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: firebase_sdk_version),
.package(url: "https://github.com/firebase/flutterfire", exact: shared_spm_version),
],
targets: [
.target(
name: "cloud_functions",
dependencies: [
.product(name: "FirebaseFunctions", package: "firebase-ios-sdk"),
// Wrapper dependency
.product(name: "firebase-core-shared", package: "flutterfire"),
],
resources: [
.process("Resources"),
],
cSettings: [
.headerSearchPath("include"),
.define("LIBRARY_VERSION", to: "\"\(library_version)\""),
.define("LIBRARY_NAME", to: "\"flutter-fire-fn\""),
]
),
]
)

0 comments on commit 548310f

Please sign in to comment.