jsdw_ios/scripts/add_app_restrict_targets.rb

153 lines
5.9 KiB
Ruby

#!/usr/bin/env ruby
# frozen_string_literal: true
require 'xcodeproj'
ROOT = File.expand_path('..', __dir__)
PROJECT_PATH = File.join(ROOT, 'QuickLocation.xcodeproj')
project = Xcodeproj::Project.open(PROJECT_PATH)
main_target = project.targets.find { |t| t.name == 'QuickLocation' }
raise 'QuickLocation target not found' unless main_target
def ensure_group(project, path_components)
group = project.main_group
path_components.each do |name|
next_group = group.children.find { |c| c.respond_to?(:name) && (c.name == name || c.path == name) }
group = next_group || group.new_group(name)
end
group
end
def add_file(project, target, group, relative_path, root:, resources: false)
abs = File.join(root, relative_path)
raise "Missing file: #{abs}" unless File.exist?(abs)
ref = group.files.find { |f| f.real_path.to_s == abs || f.path == File.basename(relative_path) }
ref ||= group.new_file(abs)
if resources
unless target.resources_build_phase.files_references.include?(ref)
target.add_resources([ref])
end
else
unless target.source_build_phase.files_references.include?(ref)
target.source_build_phase.add_file_reference(ref)
end
end
ref
end
def configure_extension_target(target, bundle_id, entitlements, info_plist)
target.build_configurations.each do |config|
bs = config.build_settings
bs['PRODUCT_BUNDLE_IDENTIFIER'] = bundle_id
bs['PRODUCT_NAME'] = target.name
bs['PRODUCT_MODULE_NAME'] = target.name
bs['CODE_SIGN_ENTITLEMENTS'] = entitlements
bs['INFOPLIST_FILE'] = info_plist
bs['GENERATE_INFOPLIST_FILE'] = 'NO'
bs['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
bs['TARGETED_DEVICE_FAMILY'] = '1'
bs['SKIP_INSTALL'] = 'YES'
bs['LD_RUNPATH_SEARCH_PATHS'] = '$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks'
bs['DEVELOPMENT_TEAM'] = 'LRDLWZ2Y83'
bs['SWIFT_DEFAULT_ACTOR_ISOLATION'] = 'nonisolated'
bs['SWIFT_VERSION'] = '5.0'
bs['CODE_SIGN_STYLE'] = 'Automatic'
bs['CURRENT_PROJECT_VERSION'] = '1'
bs['MARKETING_VERSION'] = '1.0'
end
end
def find_or_create_extension(project, name)
existing = project.targets.find { |t| t.name == name }
return existing if existing
project.new_target(:app_extension, name, :ios, '15.0')
end
def link_system_framework(target, name)
frameworks = project = target.project
frameworks_group = project.frameworks_group
path = "System/Library/Frameworks/#{name}.framework"
ref = frameworks_group.files.find { |f| f.path == "#{name}.framework" || f.name == "#{name}.framework" }
ref ||= frameworks_group.new_file(path)
ref.name = "#{name}.framework"
ref.source_tree = 'SDKROOT'
unless target.frameworks_build_phase.files_references.include?(ref)
target.frameworks_build_phase.add_file_reference(ref)
end
end
# Shared
shared_group = ensure_group(project, ['AppRestrictShared'])
add_file(project, main_target, shared_group, 'AppRestrictShared/AppRestrictShared.swift', root: ROOT)
# Main app
mgr_group = ensure_group(project, ['QuickLocation', 'Manager', 'AppRestrict'])
add_file(project, main_target, mgr_group, 'QuickLocation/Manager/AppRestrict/AppRestrictManager.swift', root: ROOT)
section_group = ensure_group(project, ['QuickLocation', 'Section', 'AppRestrict'])
%w[
AppCatalogStore.swift
AppRestrictCell.swift
AppRestrictVC.swift
AppRestrictView.swift
AppRestrictShieldSettingsVC.swift
FamilyActivityPickerHost.swift
SelectActivityVC.swift
].each do |name|
add_file(project, main_target, section_group, "QuickLocation/Section/AppRestrict/#{name}", root: ROOT)
end
add_file(project, main_target, section_group, 'QuickLocation/Section/AppRestrict/app_catalog.json', root: ROOT, resources: true)
%w[FamilyControls ManagedSettings DeviceActivity ManagedSettingsUI].each do |fw|
link_system_framework(main_target, fw)
end
# Monitor extension
monitor = find_or_create_extension(project, 'DeviceActivityMonitorExtension')
monitor_group = ensure_group(project, ['DeviceActivityMonitorExtension'])
add_file(project, monitor, monitor_group, 'DeviceActivityMonitorExtension/DeviceActivityMonitorExtension.swift', root: ROOT)
add_file(project, monitor, shared_group, 'AppRestrictShared/AppRestrictShared.swift', root: ROOT)
configure_extension_target(
monitor,
'cn.zuomeng.jisuloca.DeviceActivityMonitor',
'DeviceActivityMonitorExtension/DeviceActivityMonitorExtension.entitlements',
'DeviceActivityMonitorExtension/Info.plist'
)
%w[DeviceActivity FamilyControls ManagedSettings].each { |fw| link_system_framework(monitor, fw) }
# Shield extension
shield = find_or_create_extension(project, 'ShieldConfigurationExtension')
shield_group = ensure_group(project, ['ShieldConfigurationExtension'])
add_file(project, shield, shield_group, 'ShieldConfigurationExtension/ShieldConfigurationExtension.swift', root: ROOT)
add_file(project, shield, shared_group, 'AppRestrictShared/AppRestrictShared.swift', root: ROOT)
configure_extension_target(
shield,
'cn.zuomeng.jisuloca.ShieldConfiguration',
'ShieldConfigurationExtension/ShieldConfigurationExtension.entitlements',
'ShieldConfigurationExtension/Info.plist'
)
%w[ManagedSettings ManagedSettingsUI FamilyControls UIKit].each { |fw| link_system_framework(shield, fw) }
# Embed
embed_phase = main_target.copy_files_build_phases.find { |p| p.dst_subfolder_spec == '13' || p.name == 'Embed Foundation Extensions' }
unless embed_phase
embed_phase = main_target.new_copy_files_build_phase('Embed Foundation Extensions')
embed_phase.symbol_dst_subfolder_spec = :plug_ins
end
[monitor, shield].each do |ext|
main_target.add_dependency(ext) unless main_target.dependencies.any? { |d| d.target == ext }
product = ext.product_reference
unless embed_phase.files.any? { |f| f.file_ref == product }
bf = embed_phase.add_file_reference(product)
bf.settings = { 'ATTRIBUTES' => ['RemoveHeadersOnCopy'] }
end
end
project.save
puts 'OK: App Restrict targets wired into QuickLocation.xcodeproj'