๐Ÿ“ฆ airbnb / lottie-ios

๐Ÿ“„ Rakefile ยท 245 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245require 'json'
require 'git'

namespace :build do
  desc 'Builds all packages and executables'
  task all: ['package:all', 'example:all', 'xcframework']

  desc 'Builds the Lottie package for supported platforms'
  namespace :package do
    desc 'Builds the Lottie package for all supported platforms'
    task all: ['iOS', 'macOS', 'tvOS', 'visionOS']

    desc 'Builds the Lottie package for iOS'
    task :iOS do
      xcodebuild('build -scheme "Lottie (iOS)" -destination generic/platform=iOS -workspace Lottie.xcworkspace OTHER_SWIFT_FLAGS="-warnings-as-errors"')
    end

    desc 'Builds the Lottie package for macOS'
    task :macOS do
      xcodebuild('build -scheme "Lottie (macOS)" -destination generic/platform=macOS -workspace Lottie.xcworkspace OTHER_SWIFT_FLAGS="-warnings-as-errors"')
    end

    desc 'Builds the Lottie package for tvOS'
    task :tvOS do
      xcodebuild('build -scheme "Lottie (tvOS)" -destination generic/platform=tvOS -workspace Lottie.xcworkspace OTHER_SWIFT_FLAGS="-warnings-as-errors"')
    end

    desc 'Builds the Lottie package for visionOS'
    task :visionOS do
      xcodebuild('build -scheme "Lottie (visionOS)" -destination generic/platform=visionOS -workspace Lottie.xcworkspace OTHER_SWIFT_FLAGS="-warnings-as-errors"')
    end
  end

  desc 'Builds the Lottie example app for supported platforms'
  namespace :example do
    desc 'Builds the Lottie example apps for all supported platforms'
    task all: ['iOS', 'macOS', 'tvOS', 'visionOS']

    desc 'Builds the iOS Lottie Example app'
    task :iOS do
      xcodebuild('build -scheme "Example (Multiplatform)" -destination "platform=iOS Simulator,name=iPhone SE (3rd generation)" -workspace Lottie.xcworkspace')
    end

    desc 'Builds the macOS Lottie Example app'
    task :macOS do
      xcodebuild('build -scheme "Example (Multiplatform)" -workspace Lottie.xcworkspace')
    end

    desc 'Builds the tvOS Lottie Example app'
    task :tvOS do
      xcodebuild('build -scheme "Example (Multiplatform)" -destination "platform=tvOS Simulator,name=Apple TV" -workspace Lottie.xcworkspace')
    end

    desc 'Builds the visionOS Lottie Example app'
    task :visionOS do
      xcodebuild('build -scheme "Example (Multiplatform)" -destination "platform=visionOS Simulator,OS=26.1,name=Apple Vision Pro" -workspace Lottie.xcworkspace')
    end
  end

  desc 'Builds an xcframework for all supported platforms'
  task :xcframework, [:framework_type] do |_t, args|
    args.with_defaults(:framework_type => 'dynamic')
 
    case args[:framework_type]
    when 'dynamic'
      mach_o_type = 'mh_dylib'
      xcframework_name = 'Lottie' # Backward compatibility
    when 'static'
      mach_o_type = 'staticlib'
      xcframework_name = 'Lottie-Static'
    end

    sh 'rm -rf .build/archives'

    # Build the framework for each supported platform, including simulators
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (iOS)\" -destination generic/platform=iOS -archivePath \".build/archives/Lottie_iOS\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (iOS)\" -destination \"generic/platform=iOS Simulator\" -archivePath \".build/archives/Lottie_iOS_Simulator\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (iOS)\" -destination \"generic/platform=macOS,variant=Mac Catalyst\" -archivePath \".build/archives/Lottie_Mac_Catalyst\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (macOS)\" -destination generic/platform=macOS -archivePath \".build/archives/Lottie_macOS\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (tvOS)\" -destination generic/platform=tvOS -archivePath \".build/archives/Lottie_tvOS\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (tvOS)\" -destination \"generic/platform=tvOS Simulator\" -archivePath \".build/archives/Lottie_tvOS_Simulator\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (visionOS)\" -destination generic/platform=visionOS -archivePath \".build/archives/Lottie_visionOS\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")
    xcodebuild("archive -workspace Lottie.xcworkspace -scheme \"Lottie (visionOS)\" -destination \"generic/platform=visionOS Simulator\" -archivePath \".build/archives/Lottie_visionOS_Simulator\" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES ENABLE_BITCODE=NO SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO MACH_O_TYPE=\"#{mach_o_type}\"")

    # Combine all of the platforms into a single XCFramework
    xcframeworkInvocation = [
      '-create-xcframework',
      '-archive .build/archives/Lottie_iOS.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_iOS_Simulator.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_Mac_Catalyst.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_tvOS.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_tvOS_Simulator.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_macOS.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_visionOS.xcarchive -framework Lottie.framework',
      '-archive .build/archives/Lottie_visionOS_Simulator.xcarchive -framework Lottie.framework',
      "-output .build/artifacts/#{xcframework_name}.xcframework",
    ]

    xcodebuild(xcframeworkInvocation.join(" "))

    Dir.chdir('.build/artifacts') do
      # Codesign the XCFramework using the "Lottie iOS" certificate, which should be installed in the keychain.
      #  - Check to make sure the certificate is installed before attemtping to codesign.
      #  - In GitHub actions CI, only jobs run by contibutors have access to repo secrets,
      #    so PR jobs from external contributors won't have access to this certificate.
      #    In that case we skip codesigning so the job doesn't fail.
      puts "Checking if signing certificate is installed..."
      `security find-certificate -c 'Lottie iOS'`
      if $?.success?
        puts "Signing certificate is installed. Code signing Lottie.xcframework."
        sh "codesign --timestamp -v --sign \"Lottie iOS\" #{xcframework_name}.xcframework"
      else
        puts "Signing certificate is not installed. #{xcframework_name}.xcframework will not be code signed."
      end

      # Archive the XCFramework into a zip file
      # Use --symlinks to avoid "Multiple binaries share the same codesign path. This can happen if your build process copies frameworks by following symlinks." 
      # error when validating macOS apps (#1948)
      sh "zip -r --symlinks #{xcframework_name}.xcframework.zip #{xcframework_name}.xcframework"
      sh "rm -rf #{xcframework_name}.xcframework"
    end

    sh "swift package compute-checksum .build/artifacts/#{xcframework_name}.xcframework.zip"
  end
end

namespace :test do
  desc 'Tests the Lottie package for iOS'
  task :package do
    sh 'rm -rf Tests/Artifacts'
    xcodebuild('test -scheme "Lottie (iOS)" -destination "platform=iOS Simulator,name=iPhone SE (3rd generation)" -resultBundlePath Tests/Artifacts/LottieTests.xcresult')
  end

  desc 'Processes .xcresult artifacts from the most recent test:package execution'
  task :process do
    sh 'mint run ChargePoint/xcparse@2.3.1 xcparse attachments Tests/Artifacts/LottieTests.xcresult Tests/Artifacts/TestAttachments'
  end

  desc 'Tests Carthage support'
  task :carthage do
    # Copy the repo to `Carthage/Checkouts/Lottie-ios`
    sh 'rm -rf script/test-carthage/Carthage'
    sh 'mkdir script/test-carthage/Carthage script/test-carthage/Carthage/Checkouts script/test-carthage/Carthage/Checkouts/lottie-ios'
    sh 'cp -R [^script]* script/test-carthage/Carthage/Checkouts/lottie-ios'

    Dir.chdir('script/test-carthage') do
      # Build the Lottie framework scheme
      sh 'carthage build --use-xcframeworks'

      # Delete Carthage's derived data to verify that the built .xcframework doesn't depend on any
      # side effects from building on this specific machine.
      # https://github.com/airbnb/lottie-ios/issues/1492
      sh 'rm -rf ~/Library/Caches/org.carthage.CarthageKit/DerivedData'

      # Build a test app that imports and uses the Lottie framework built via Carthage
      xcodebuild('build -scheme CarthageTest  -destination "platform=iOS Simulator,name=iPhone SE (3rd generation)"')
      xcodebuild('build -scheme CarthageTest -destination generic/platform=macOS')
      xcodebuild('build -scheme CarthageTest -destination "platform=tvOS Simulator,name=Apple TV"')
      xcodebuild('build -scheme CarthageTest -destination "platform=visionOS Simulator,OS=26.1,name=Apple Vision Pro"')
    end
  end

  desc 'Tests Swift Package Manager support'
  task :spm do
    Dir.chdir('script/test-spm') do
      # Build for iOS, macOS, and tvOS using the targets defined in Package.swift
      xcodebuild('build -scheme "Lottie" -destination generic/platform=iOS')
      xcodebuild('build -scheme "Lottie" -destination generic/platform=macOS')
      xcodebuild('build -scheme "Lottie" -destination generic/platform=tvOS')
      xcodebuild('build -scheme "Lottie" -destination generic/platform=visionOS')
    end
  end
end

namespace :lint do
  desc 'Lints swift files'
  task :swift do
    sh 'swift package --allow-writing-to-package-directory format --lint'
  end

  desc 'Lints the CocoaPods podspec'
  task :podspec do
    sh 'pod lib lint lottie-ios.podspec'
  end

  desc 'Lints the EmbeddedLibraries directory'
  task :EmbeddedLibraries do
    sh 'echo "Linting /Sources/Private/EmbeddedLibraries (should not contain any public symbols)"'
    sh '! grep -r "public" Sources/Private/EmbeddedLibraries --include \*.swift'
  end
end

namespace :format do
  desc 'Formats swift files'
  task :swift do
    sh 'swift package --allow-writing-to-package-directory format'
  end
end

namespace :emerge do
  desc 'Uploads to emerge'
  task :upload do
    xcodebuild('build -scheme "SizeTest" -destination generic/platform=iOS -project script/SizeTest/SizeTest.xcodeproj -archivePath test.xcarchive archive CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO')
    sh "zip -r -qq test.zip test.xcarchive"

    g = Git.open('.')

    upload_data = {
      repoName: 'airbnb/lottie-ios',
      filename: 'test.zip'
    }
    if ENV["PR_NUMBER"] != "" && ENV["PR_NUMBER"] != "false"
      upload_data[:sha] = g.log[0].parents[1].sha
      upload_data[:baseSha] = g.log[0].parent.sha
      upload_data[:prNumber] = ENV["PR_NUMBER"]
      upload_data[:buildType] = 'pull_request'
    else
      upload_data[:sha] = g.log[0].sha
      upload_data[:buildType] = 'master'
    end
    api_token = ENV['EMERGE_API_TOKEN']
    if api_token.nil? || api_token.empty?
      puts "Skipping Emerge upload because API token was not provided."
      next
    end
    api_token_header = "X-API-Token: #{api_token}"
    url = "https://api.emergetools.com/upload"
    cmd = "curl --fail -s --request POST --url #{url} --header 'Accept: application/json' --header 'Content-Type: application/json' --header '#{api_token_header}' --data '#{upload_data.to_json}'"
    upload_json = %x(#{cmd})
    upload_url = JSON.parse(upload_json)['uploadURL']
    %x(curl --fail -s -H 'Content-Type: application/zip' -T test.zip '#{upload_url}')
  end
end

def xcodebuild(command)
  # Check if the mint tool is installed -- if so, pipe the xcodebuild output through xcbeautify
  `which mint`

  if $?.success?
    sh "set -o pipefail && xcodebuild #{command} | mint run thii/xcbeautify@0.10.2"
  else
    sh "xcodebuild #{command}"
  end
end