Writing in the front
This article is mainly based on the need to generate customizations using the same set of code without package names, different developer certificates, different features, different component dependencies, different extensions, multiple targets, etc.
Environmental installation
- Install Cocoapods. If none of this is installed, you don’t need to look behind you.
- Install the Ruby library XcodeProj, see XcodeProj Github for details.
Custom packaging
Load the configuration of xxx.project
project_path = 'xxx.xcodeproj'
project = Xcodeproj::Project.open(project_path)
Copy the code
2. Modify the build setting of a Target of the project
project.targets.each do |target|
#your target name
if target.name == 'Scene'
target.build_configurations.each do |config|
# Debug / Release
if config.name == 'Release'
Get build Settings
build_settings = config.build_settings
#build_settings is a hash that contains individual configurations
build_settings.each do |key,value|
print key, "= =", value, "\n"
# you can set the certificate here.
Change the bundle ID and test it
# build_settings[key] = "com.test.demo"
Set the license file
# build_settings["CODE_SIGN_ENTITLEMENTS"] = "xxx.entitlements"
Set signature iPhone Distribution/iPhone Developer
build_settings["PROVISIONING_PROFILE_SPECIFIER"] = "PROFILENAME"
build_settings["PRODUCT_BUNDLE_IDENTIFIER"] = "your BUNDLEID"
build_settings["DEVELOPMENT_TEAM"] = "your TEAMID"
#... Others look up the API as required
end
end
end
end
Copy the code
3. Rely on and unrely on Extension
def updateDependecies(mode, project, app_target_name, ext)
require 'xcodeproj'
# Find project and app target
puts mode
xc = project
app_target = xc.targets.find { |t| t.name == app_target_name }
# Find app extensions' target objects
target = xc.targets.find { |t| t.name == ext }
return "Couldn't find a '#{ext}' target in '#{app_target_name}'" if target.nil?
return "'#{ext}' doesn't seem to be an application extension target" unless target.product_type.include? 'app-extension'
target
# Find .appex product files
appex = target.product_reference
# Add or remove dependency on extension targets
dependency = app_target.dependency_for_target(target)
puts app_target.dependencies
if mode == 'add'
if dependency
puts "[WARN] App already has dependency on #{target.name}"
else
app_target.add_dependency(target)
end
else
if dependency
app_target.dependencies.delete(dependency)
else
puts "[WARN] Couldn't find dependency on #{target.name}"
end
end
# Add or remove .appex copy jobs
embed_extensions_phase = app_target.copy_files_build_phases.find do |copy_phase|
copy_phase.symbol_dst_subfolder_spec == :plug_ins
end
return "Couldn't find 'Embed App Extensions' phase" if embed_extensions_phase.nil?
appex_included = embed_extensions_phase.files_references.include? appex
if mode == 'add'
if appex_included
puts "[WARN] App already embeds #{appex.display_name}"
else
build_file = embed_extensions_phase.add_file_reference(appex)
build_file.settings = { "ATTRIBUTES"= > ['RemoveHeadersOnCopy'] }
end
else
if appex_included
embed_extensions_phase.remove_file_reference(appex)
else
puts "[WARN] App doesn't seem to embed #{appex.display_name}"
end
end
return Update dependency '#{ext}' target in '#{app_target_name}'"
end
Copy the code
Add/remove framework to Target
- The relevant knowledge Refer to the address
Link binary with libraries system libraries, link them.
Embed Frameworks 3rd party libraries, embed them.
- Add or remove a system framework
def exsit_framework? (build_phase,name)# next ! if build_phase.nil?
build_phase.files_references.each do |ref|
if ref.name == "#{name}"
puts "Existing #{name}"
return true
end
end
puts "There is no #{name}"
return false
end
def updateSystemFramework(project,target,name, command)
require 'xcodeproj'
puts "#{command} #{name} to #{target}"
build_phase = target.frameworks_build_phase
framework_group = project.frameworks_group
if command == :add
ifself.exsit_framework? (build_phase,name)return
end
systempath = "System/Library/Frameworks/"
path = "#{systempath}#{name}"
file_ref = framework_group.new_reference(path)
file_ref.name = "#{name}"
file_ref.source_tree = 'SDKROOT'
build_file = build_phase.add_file_reference(file_ref)
else
build_phase.files_references.each do |ref|
if ref.name == "#{name}"
puts Delete "# {name}"
build_phase.remove_file_reference(ref)
framework_group.children.delete(ref)
break
end
end
end
end
Copy the code
- Add or remove custom framework and lib
def updateCustomFramework(project,target, path,name,command)
# Get useful variables
frameworks_group = project.groups.find { |group| group.display_name == 'Frameworks' }
frameworks_build_phase = target.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }
embed_frameworks_build_phase = nil
target.build_phases.each do |phase|
if phase.display_name == 'Embed Frameworks'
embed_frameworks_build_phase = phase
end
# puts phase
end
if command == :add
# Add new "Embed Frameworks" build phase to target
if embed_frameworks_build_phase.nil?
embed_frameworks_build_phase = project.new(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase)
embed_frameworks_build_phase.name = 'Embed Frameworks'embed_frameworks_build_phase.symbol_dst_subfolder_spec = :frameworks target.build_phases << embed_frameworks_build_phase end# Add framework search path to target
['Debug'.'Release'].each do |config|
paths = ['$(inherited)', path]
orgpath = target.build_settings(config)['FRAMEWORK_SEARCH_PATHS']
if orgpath.nil?
puts "Path is empty ----------"
target.build_settings(config)['FRAMEWORK_SEARCH_PATHS'] = paths
else
puts "Path not empty ----------"
paths.each do |p|
if! orgpath.include? (p) orgpath << p end end end end# Add framework to target as "Embedded Frameworks"
framework_ref = frameworks_group.new_file("#{path}#{name}")
exsit = false
embed_frameworks_build_phase.files_references.each do |ref|
if ref.name = name
exsit = true
end
end
if! exsit build_file = embed_frameworks_build_phase.add_file_reference(framework_ref) frameworks_build_phase.add_file_reference(framework_ref) build_file.settings = {'ATTRIBUTES'= > ['CodeSignOnCopy'] }
end
else
frameworks_build_phase.files_references.each do |ref|
if ref.name == "#{name}"
puts Delete "# {name}"
frameworks_build_phase.remove_file_reference(ref)
embed_frameworks_build_phase.remove_file_reference(ref)
break
end
end
end
end
Copy the code
Enable SystemCapabilities
For example: AccessWiFi
# an argument passed in from outside
wifiFlag = ARGV[0]
project.objects.each do |obj|
if obj.isa == "PBXProject"
systemCapabilities = obj.attributes["TargetAttributes"][ta.uuid]["SystemCapabilities"]
puts systemCapabilities
systemCapabilities["com.apple.AccessWiFi"] = {"enabled":"#{wifiFlag}"}
end
end
Copy the code
Dynamically modify component dependencies
- The original idea is to use the sed command to replace the string directly as follows:
target 'Scene' do
pod 'iOSExtension/Widgets',:path => '.. / '
pod 'XXX'
pod 'YYY'
pod 'AAA'
pod 'BBB'
end
Copy the code
Use the sed command to delete the specified line of package name XXX
$sed -i ' ' "/XXX.*/d" filePath
Copy the code
- Although the above specified we achieve the effect, but some scenes below, it seems a little ugly. For example, in some circumstances, our pod library for a module would look like this if we followed the script above:
$sed -i ' ' "/XXX.*/d" filePath
$sed -i ' ' "/YYY.*/d" filePath
$sed -i ' ' "/AAA.*/d" filePath
$sed -i ' ' "/BBB.*/d" filePath
Copy the code
In fact, the Podfile itself is a Ruby file, so you can define functions in it. In this case, to solve the problem of removing multiple POD libraries, you can define a function
def myPodModule(flag)
if flag == 0
puts "No -- install myPodModule"
return
end
pod 'XXX'
pod 'YYY'
pod 'AAA'
pod 'BBB'
puts "Install myPodModule"
end
target 'Scene' do
pod 'iOSExtension/Widgets',:path => '.. / '
# call
myPodModule(1)
end
Copy the code
The script is as follows:
# dependent scripts
$sed -i "" 's/myPodModule(0)/myPodModule(1)/g' xxx/Podfile
# undependent scripts
$sed -i "" 's/myPodModule(1)/myPodModule(0)/g' xxx/Podfile
Copy the code
Multitarget component dependencies
The structure of the original Podfile is as follows:
target 'Scene' do
pod 'iOSExtension/Widgets',:path => '.. / '
end
target 'Widgets' do
pod 'my/Wiget',:path => '.. / '
end
Copy the code
The script at this point makes me sick. In fact, you can also use the above ideas to encapsulate
def widgets(flag)
if flag == 0
puts "No -- install dependencies for Widgets Target"
return
end
target 'Widgets' do
pod 'my/Wiget',:path => '.. / '
end
end
target 'Scene' do
pod 'iOSExtension/Widgets',:path => '.. / '
end
# call
widgets(1)
Copy the code
The script is as follows:
# dependent scripts
$sed -i "" 's/widgets(0)/widgets(1)/g' xxx/Podfile
# undependent scripts
$sed -i "" 's/widgets(1)/widgets(0)/g' xxx/Podfile
Copy the code
More Podfile SAO operations
- hook Podfile
post_install do |installer|
project = installer.aggregate_targets.first.user_project
project.targets.each do |target|
puts target.name,'Name:'
end
end
Copy the code
For more information
Xcodeproj making address
Xcodeproj API documentation
The last
fuck996