fastlane-plugin-build_xcframework 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 692809331fa5197fab9b15a5aef97870097cde17bf3317fafd5f295b5fee9ff7
4
+ data.tar.gz: 0602bf78276e4a3b31a92a66b7429e9ba5a1189bda1a68148aef7471b4d087fb
5
+ SHA512:
6
+ metadata.gz: 4fde38204ec0e659645d181cac3a0c8c004494750e0e850e9e70f8b1cad9f767debfd9c94216b8a1af4f8a2a9dab807b6afc013453e05fc376db6a88806069ad
7
+ data.tar.gz: 0b96f623318cb4d4826a3900ce25a27241262e08338be193fe9d91a533ab623b9781d24d72e362ec1fd8f328f314863967a1c69d946a627abe3a02d9d633c99d
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Alex Crowe <alexei.hmelevski@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # build_xcframework plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-build_xcframework)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-build_xcframework`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin build_xcframework
11
+ ```
12
+
13
+ ## About build_xcframework
14
+
15
+ This plugin provides high-level api for creating xcframework
16
+
17
+ **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
18
+
19
+ ## Example
20
+
21
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
22
+
23
+ **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
24
+
25
+ ## Run tests for this plugin
26
+
27
+ To run both the tests, and code style validation, run
28
+
29
+ ```
30
+ rake
31
+ ```
32
+
33
+ To automatically fix many of the styling issues, use
34
+ ```
35
+ rubocop -a
36
+ ```
37
+
38
+ ## Issues and Feedback
39
+
40
+ For any other issues and feedback about this plugin, please submit it to this repository.
41
+
42
+ ## Troubleshooting
43
+
44
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
45
+
46
+ ## Using _fastlane_ Plugins
47
+
48
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
49
+
50
+ ## About _fastlane_
51
+
52
+ _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -0,0 +1,20 @@
1
+ require 'fastlane/action'
2
+
3
+ module Fastlane
4
+ module Actions
5
+ class BuildUtils
6
+ def self.prepare(config)
7
+ UI.important("Preparing folders")
8
+ UI.message("Removing old: #{config[:base]}")
9
+ FileUtils.rm_rf(config[:release_folder])
10
+ UI.message("Creating empty: #{config[:release_folder]}")
11
+ Actions.sh("set -o pipefail && mkdir -p #{config[:release_folder]}")
12
+ end
13
+
14
+ def self.clean_temp_folder(config)
15
+ UI.message("Clearing derived data folder: #{config[:derived_data]}")
16
+ FileUtils.rm_rf(config[:derived_data])
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,144 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/helper_object'
3
+ require_relative './path_builder'
4
+ require_relative './lipo_runner'
5
+ require_relative './build_utils'
6
+ require_relative './xconfig_builder'
7
+ require_relative './xcframework_builder'
8
+
9
+ module Fastlane
10
+ module Actions
11
+ class BuildXcframeworkAction < Action
12
+ def self.build_xcframework(params)
13
+ UI.message("Started building #{XconfigBuilder.paths_components[:project_name]}.#{params[:type]} for #{params[:sdk]} support")
14
+ Actions::XcodebuildAction.run(params)
15
+ UI.message("Finished building #{XconfigBuilder.paths_components[:project_name]}.#{params[:type]} for #{params[:sdk]} support")
16
+ end
17
+
18
+ def self.run(params)
19
+ if params[:type] != 'framework' && params[:type] != 'xcframework'
20
+ UI.error("Unsupported framework type of: #{params[:type]}")
21
+ return
22
+ end
23
+
24
+ UI.message('Building paths components')
25
+ paths_components = get_paths_components(params)
26
+ if paths_components.nil?
27
+ return
28
+ end
29
+
30
+ Actions::BuildUtils.prepare(paths_components)
31
+ UI.message('Building paths components finished')
32
+
33
+ XconfigBuilder.params = params
34
+ XconfigBuilder.paths_components = paths_components
35
+
36
+ build_for_sim_if_required(params)
37
+
38
+ UI.success("Building for device")
39
+ build_for_device
40
+
41
+ if params[:type] == 'framework'
42
+ lipo_config = Helper::Object.copy(paths_components)
43
+ lipo_config[:includeSimulator] = params[:includeSimulator]
44
+ Actions::LipoRunner.run(lipo_config)
45
+ else
46
+ Actions::XCFrameworkBuilder.run(paths_components)
47
+ end
48
+ Actions::BuildUtils.clean_temp_folder(paths_components)
49
+ UI.success("Build succeed")
50
+ end
51
+
52
+ def self.build_for_device
53
+ xcodebuild_configs = XconfigBuilder.device_config
54
+ build_xcframework(xcodebuild_configs)
55
+ end
56
+
57
+ def self.build_for_sim_if_required(params)
58
+ if params[:includeSimulator] || params[:type] == 'xcframework'
59
+ UI.message("Building for sim")
60
+ xcodebuild_configs = XconfigBuilder.simulator_config
61
+ build_xcframework(xcodebuild_configs)
62
+ end
63
+ end
64
+
65
+ def self.get_paths_components(params)
66
+ builder_config = {}
67
+ builder_config[:project] = params[:project]
68
+ builder_config[:workspace] = params[:workspace]
69
+ PathBuilder.build_paths(params)
70
+ end
71
+
72
+ def self.authors
73
+ ["Alex Crowe"]
74
+ end
75
+
76
+ def self.details
77
+ # Optional:
78
+ "It encapsulates xcbuild to provide simple api to create xcframework"
79
+ end
80
+
81
+ def self.available_options
82
+ [
83
+ FastlaneCore::ConfigItem.new(key: :project,
84
+ description: "Project name",
85
+ optional: true,
86
+ type: String),
87
+ FastlaneCore::ConfigItem.new(key: :output_folder,
88
+ description: "Output folder",
89
+ default_value: "./fastlane_build",
90
+ optional: true,
91
+ type: String),
92
+
93
+ FastlaneCore::ConfigItem.new(key: :workspace,
94
+ description: "Workspace name",
95
+ optional: true,
96
+ type: String),
97
+
98
+ FastlaneCore::ConfigItem.new(key: :scheme,
99
+ description: "Scheme name",
100
+ optional: true,
101
+ type: String),
102
+
103
+ FastlaneCore::ConfigItem.new(key: :configuration,
104
+ description: "Build Configuration",
105
+ default_value: 'Release',
106
+ optional: true,
107
+ type: String),
108
+
109
+ FastlaneCore::ConfigItem.new(key: :sim_configuration,
110
+ description: "Sim Build Configuration",
111
+ default_value: 'Release',
112
+ optional: true,
113
+ type: String),
114
+
115
+ FastlaneCore::ConfigItem.new(key: :type,
116
+ description: "Framework type",
117
+ optional: true,
118
+ default_value: 'xcframework',
119
+ type: String),
120
+
121
+ FastlaneCore::ConfigItem.new(key: :includeSimulator,
122
+ description: "Include simulator support",
123
+ optional: true,
124
+ default_value: false,
125
+ is_string: false),
126
+
127
+ FastlaneCore::ConfigItem.new(key: :dev_archs,
128
+ description: "Build for device architectures",
129
+ optional: true,
130
+ type: Array),
131
+
132
+ FastlaneCore::ConfigItem.new(key: :sim_archs,
133
+ description: "Build for sim architectures",
134
+ optional: true,
135
+ type: Array)
136
+ ]
137
+ end
138
+
139
+ def self.is_supported?(platform)
140
+ [:ios, :mac].include?(platform)
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,25 @@
1
+ require 'fastlane/action'
2
+
3
+ module Fastlane
4
+ module Actions
5
+ class LipoRunner
6
+ def self.run(config)
7
+ Actions.sh("set -o pipefail && cp -r #{config[:device_framework_filename]} #{config[:release_framework_filename]}")
8
+ release_binary_path = binary_path(config[:release_framework_filename], config[:project_name])
9
+ temp_device_binary_path = binary_path(config[:device_framework_filename], config[:project_name])
10
+ args = release_binary_path + ' ' + temp_device_binary_path
11
+
12
+ if config[:includeSimulator]
13
+ UI.message('merging with simulator')
14
+ sim_binary_path = binary_path(config[:sim_framework_filename], config[:project_name])
15
+ args += " #{sim_binary_path}"
16
+ end
17
+ Actions.sh("set -o pipefail && lipo -create -output #{args}")
18
+ end
19
+
20
+ def self.binary_path(filename, proejct_name)
21
+ "#{filename}/#{proejct_name}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,88 @@
1
+ require "pathname"
2
+
3
+ module Fastlane
4
+ class PathBuilder
5
+ def self.build_paths(config)
6
+ base = config[:output_folder]
7
+ derived = base + '/derivedData'
8
+ file_name = config[:project] || config[:workspace] || detect_file("*.xcworkspace") || detect_file("*.xcodeproj")
9
+
10
+ UI.important("Detected file name: #{file_name}")
11
+
12
+ configuration = config[:configuration]
13
+ sim_configuration = config[:sim_configuration]
14
+ name = ''
15
+
16
+ path = Pathname.new(file_name)
17
+ file_name = path.basename.to_s || file_name
18
+ if file_name
19
+ name = file_name.split('.').first
20
+ end
21
+
22
+ if name.nil? || name.empty?
23
+ UI.error("Could not find project or workspace")
24
+ raise StandardError, "Could not find project or workspace"
25
+ end
26
+
27
+ UI.important("Detected project name: #{name}")
28
+ framework_name = name + '.framework'
29
+ xcframework_name = name + '.xcframework'
30
+ release_folder = base
31
+
32
+ temp_folder_config = {
33
+ derived: derived,
34
+ name: name
35
+ }
36
+
37
+ sim_temp_folder_cfg = deep_clone(temp_folder_config)
38
+ sim_temp_folder_cfg[:os] = 'iphonesimulator'
39
+ sim_temp_folder_cfg[:config] = sim_configuration
40
+
41
+ dev_temp_folder_cfg = deep_clone(temp_folder_config)
42
+ dev_temp_folder_cfg[:os] = 'iphoneos'
43
+ dev_temp_folder_cfg[:config] = configuration
44
+
45
+ {
46
+ out_base: base,
47
+ derived_data: derived,
48
+ buildlog_path: derived + "/logs",
49
+ project_name: name,
50
+ release_folder: release_folder,
51
+ release_framework_filename: release_folder + "/#{framework_name}",
52
+ release_xcframework_filename: release_folder + "/#{xcframework_name}",
53
+ device_framework_filename: temp_folder(dev_temp_folder_cfg) + "/#{framework_name}",
54
+ sim_framework_filename: temp_folder(sim_temp_folder_cfg) + "/#{framework_name}",
55
+ build_path_device: temp_folder(dev_temp_folder_cfg).to_s,
56
+ build_path_sim: temp_folder(sim_temp_folder_cfg).to_s
57
+ }
58
+ end
59
+
60
+ def self.deep_clone(obj)
61
+ obj.clone.tap do |new_obj|
62
+ new_obj.each do |key, val|
63
+ new_obj[key] = deep_clone(val) if val.kind_of?(Hash)
64
+ end
65
+ end
66
+ end
67
+
68
+ def self.temp_folder(cfg)
69
+ return cfg[:derived] + "/#{cfg[:os]}/#{cfg[:name]}.xcarchive/Products/Library/Frameworks"
70
+ end
71
+
72
+ def self.detect_file(name)
73
+ file = nil
74
+ files = Dir.glob(name)
75
+
76
+ if files.length > 1
77
+ UI.important("Multiple files detected.")
78
+ end
79
+
80
+ unless files.empty?
81
+ file = files.first
82
+ UI.important("Using file \"#{file}\"")
83
+ end
84
+
85
+ return file
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,18 @@
1
+ require 'fastlane/action'
2
+
3
+ module Fastlane
4
+ module Actions
5
+ class XCFrameworkBuilder
6
+ def self.run(config)
7
+ temp_device_framework = config[:device_framework_filename]
8
+ temp_sim_framework = config[:sim_framework_filename]
9
+ framework_command_args = [temp_device_framework, temp_sim_framework].compact.reduce('') { |sum, cur| sum + " -framework " + cur }
10
+ Actions.sh("set -o pipefail && xcodebuild -create-xcframework #{framework_command_args} -output #{config[:release_xcframework_filename]}")
11
+ end
12
+
13
+ def self.framework_temp_path(base, name)
14
+ "#{base}/Products/Library/Frameworks/#{name}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,89 @@
1
+ module Fastlane
2
+ class XconfigBuilder
3
+ @paths_components = {}
4
+ @params = {}
5
+
6
+ class << self
7
+ attr_reader :params
8
+ attr_writer(:params)
9
+ attr_reader :paths_components
10
+ attr_writer(:paths_components)
11
+ end
12
+
13
+ def self.prepare_config(simulator)
14
+ xcodebuild_configs = base_config
15
+ archs = params[:sim_archs]
16
+
17
+ if simulator == true
18
+ xcodebuild_configs[:sdk] = 'iphonesimulator'
19
+ xcodebuild_configs[:configuration] = params[:configuration]
20
+
21
+ archs = params[:sim_archs]
22
+ else
23
+ xcodebuild_configs[:sdk] = 'iphoneos'
24
+ xcodebuild_configs[:configuration] = params[:sim_configuration]
25
+ archs = params[:dev_archs]
26
+ end
27
+ # if params[:type] == 'xcframework'
28
+ path = "#{paths_components[:derived_data]}/#{xcodebuild_configs[:sdk]}/#{paths_components[:project_name]}"
29
+ xcodebuild_configs[:archive_path] = path
30
+ destination = ''
31
+ if simulator
32
+ destination = "generic/platform=iOS Simulator"
33
+ else
34
+ destination = "generic/platform=iOS"
35
+ end
36
+ xcodebuild_configs[:destination] = destination
37
+ # end
38
+
39
+ if archs
40
+ xcodebuild_configs[:xcargs] += ' ' + archs.reduce('') { |sum, cur| sum + " -arch " + cur }
41
+ end
42
+ if simulator == true && params[:type] == 'framework'
43
+ xcodebuild_configs[:xcargs] += ' ' + "EXCLUDED_ARCHS=\"arm64\""
44
+ end
45
+ xcodebuild_configs
46
+ end
47
+
48
+ def self.simulator_config
49
+ prepare_config(true)
50
+ end
51
+
52
+ def self.device_config
53
+ prepare_config(false)
54
+ end
55
+
56
+ def self.base_config
57
+ case params[:type]
58
+ when 'framework'
59
+ xcodebuild_configs = static_framework_settings
60
+ # xcodebuild_configs[:derivedDataPath] = paths_components[:derived_data]
61
+ when 'xcframework'
62
+ xcodebuild_configs = xc_framework_settings
63
+ else
64
+ xcodebuild_configs = {}
65
+ end
66
+ xcodebuild_configs[:project] = params[:project]
67
+ xcodebuild_configs[:workspace] = params[:workspace]
68
+ xcodebuild_configs[:scheme] = params[:scheme] || paths_components[:project_name]
69
+ xcodebuild_configs[:xcargs] = ''
70
+ xcodebuild_configs
71
+ end
72
+
73
+ def self.static_framework_settings
74
+ {
75
+ only_active_arch: false,
76
+ archive: true,
77
+ defines_module: false
78
+ }
79
+ end
80
+
81
+ def self.xc_framework_settings
82
+ {
83
+ only_active_arch: false,
84
+ archive: true,
85
+ defines_module: false
86
+ }
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,13 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
5
+
6
+ module Helper
7
+ class BuildXcframeworkHelper
8
+ def self.show_message
9
+ UI.message("Hello from the build_xcframework plugin helper!")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ module Helper
5
+ class Object
6
+ def self.copy(obj)
7
+ obj.clone.tap do |new_obj|
8
+ new_obj.each do |key, val|
9
+ new_obj[key] = deep_clone(val) if val.kind_of?(Hash)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module BuildXcframework
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/build_xcframework/version'
2
+
3
+ module Fastlane
4
+ module BuildXcframework
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::BuildXcframework.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-build_xcframework
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Crowe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-03-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pathname
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.0
27
+ description:
28
+ email: alexei.hmelevski@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - LICENSE
34
+ - README.md
35
+ - lib/fastlane/plugin/build_xcframework.rb
36
+ - lib/fastlane/plugin/build_xcframework/actions/build_utils.rb
37
+ - lib/fastlane/plugin/build_xcframework/actions/build_xcframework_action.rb
38
+ - lib/fastlane/plugin/build_xcframework/actions/lipo_runner.rb
39
+ - lib/fastlane/plugin/build_xcframework/actions/path_builder.rb
40
+ - lib/fastlane/plugin/build_xcframework/actions/xcframework_builder.rb
41
+ - lib/fastlane/plugin/build_xcframework/actions/xconfig_builder.rb
42
+ - lib/fastlane/plugin/build_xcframework/helper/build_xcframework_helper.rb
43
+ - lib/fastlane/plugin/build_xcframework/helper/helper_object.rb
44
+ - lib/fastlane/plugin/build_xcframework/version.rb
45
+ homepage: https://github.com/Swift-Gurus/fastlane_build_xcframework
46
+ licenses:
47
+ - MIT
48
+ metadata:
49
+ rubygems_mfa_required: 'true'
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '2.6'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.3.7
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: This plugin provides high-level api for creating xcframework
69
+ test_files: []