Created
March 29, 2025 12:51
-
-
Save cristiangu/17b2be4759634f0eef7b56bca514e383 to your computer and use it in GitHub Desktop.
Update an IPA file with a new React Native JS bundle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Fastlane | |
module Actions | |
module SharedValues | |
REFRESH_IPA_JS_BUNDLE_CUSTOM_VALUE = :REFRESH_IPA_JS_BUNDLE_CUSTOM_VALUE | |
end | |
class RefreshIpaJsBundleAction < Action | |
def self.run(params) | |
require 'fastlane/actions/resign' | |
unzipped_path = "./ipa_unzipped" | |
js_bundle_dir = "#{unzipped_path}/Payload/mobile_app.app" | |
js_bundle_path = "#{js_bundle_dir}/main.jsbundle" | |
sh("unzip mobile_app.ipa -d #{unzipped_path}") | |
sh("rm -rf mobile_app.ipa") | |
sh("rm -rf #{js_bundle_path}") | |
UI.message("Creating a new unminified JS bundle") | |
sh("yarn react-native bundle \ | |
--dev false \ | |
--minify false \ | |
--platform ios \ | |
--entry-file index.js \ | |
--reset-cache \ | |
--bundle-output main.jsbundle \ | |
--sourcemap-output main.jsbundle.map") | |
UI.message("Compiling JS bundle to Hermes bytecode") | |
sh("ios/Pods/hermes-engine/destroot/bin/hermesc \ | |
-O -emit-binary \ | |
-output-source-map \ | |
-out=main.jsbundle.hbc \ | |
main.jsbundle") | |
sh("rm -f main.jsbundle") | |
sh("mv main.jsbundle.hbc main.jsbundle") | |
UI.message("Copying JS bundle to IPA") | |
sh("cp main.jsbundle #{js_bundle_path}") | |
#other_action.sentry_upload_sourcemaps( | |
# bundle_name: "main.jsbundle", | |
# release: "mobile-app@#{ENV["APP_VERSION"]}+#{params[:build_number]}", | |
#) | |
sh("cd #{unzipped_path} && zip -r ../mobile_app.ipa ./*") | |
UI.message("Resigning IPA, setting app version and incrementing build number") | |
UI.message("IPA file: mobile_app.ipa") | |
UI.message("App version: #{ENV["APP_VERSION"]}") | |
UI.message("Build number: #{params[:build_number]}") | |
Fastlane::Actions::ResignAction.run( | |
ipa: "./mobile_app.ipa", | |
short_version: ENV["APP_VERSION"], | |
bundle_version: params[:build_number], | |
signing_identity: ENV["sigh_com.bundle.identifier_#{params[:match_type]}_certificate-name"], | |
provisioning_profile: { | |
"com.bundle.identifier" => ENV["sigh_com.bundle.identifier_#{params[:match_type]}_profile-path"], | |
"com.bundle.identifier.NotificationService" => ENV["sigh_com.bundle.identifier.NotificationService_#{params[:match_type]}_profile-path"] | |
}, | |
# Use the local app entitlement file(s), useful for multiple entitlement files. (App + Extensions) | |
use_app_entitlements: true | |
) | |
end | |
##################################################### | |
# @!group Documentation | |
##################################################### | |
def self.description | |
'A short description with <= 80 characters of what this action does' | |
end | |
def self.details | |
# Optional: | |
# this is your chance to provide a more detailed description of this action | |
'You can use this action to do cool things...' | |
end | |
def self.available_options | |
# Define all options your action supports. | |
# Below a few examples | |
[ | |
FastlaneCore::ConfigItem.new(key: :build_number, | |
# The name of the environment variable | |
env_name: 'FL_REFRESH_IPA_JS_BUNDLE_BUILD_NUMBER', | |
# a short description of this parameter | |
description: 'Build number for the new IPA', | |
verify_block: proc do |value| | |
unless value && !value.empty? | |
UI.user_error!("No build number for RefreshIpaJsBundleAction given, pass using `build_number: '231'`") | |
end | |
# UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value) | |
end), | |
FastlaneCore::ConfigItem.new(key: :match_type, | |
# The name of the environment variable | |
env_name: 'FL_REFRESH_IPA_JS_BUNDLE_MATCH_TYPE', | |
# a short description of this parameter | |
description: 'Match type for the new IPA, can be adhoc or appstore', | |
verify_block: proc do |value| | |
unless value && !value.empty? | |
UI.user_error!("No match type for RefreshIpaJsBundleAction given, pass using `match_type: 'adhoc'`") | |
end | |
# UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value) | |
end), | |
] | |
end | |
def self.output | |
# Define the shared values you are going to provide | |
# Example | |
# [ | |
# ['REFRESH_IPA_JS_BUNDLE_CUSTOM_VALUE', 'A description of what this value contains'] | |
# ] | |
end | |
def self.return_value | |
# If your method provides a return value, you can describe here what it does | |
end | |
def self.authors | |
# So no one will ever forget your contribution to fastlane :) You are awesome btw! | |
['https://github.com/cristiangu'] | |
end | |
def self.is_supported?(platform) | |
# you can do things like | |
# | |
# true | |
# | |
# platform == :ios | |
# | |
# [:ios, :mac].include?(platform) | |
# | |
platform == :ios | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment