diff --git a/.rubocop.yml b/.rubocop.yml index eb840c535..281154b70 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -24,10 +24,17 @@ Metrics/MethodLength: Enabled: false Metrics/CyclomaticComplexity: - AllowedMethods: [make_project!, react_native_pods, use_test_app_internal!] + AllowedMethods: + - generate_info_plist! + - make_project! + - react_native_pods + - use_test_app_internal! Metrics/PerceivedComplexity: - AllowedMethods: [make_project!, react_native_pods, use_test_app_internal!] + AllowedMethods: + - make_project! + - react_native_pods + - use_test_app_internal! Naming/FileName: Exclude: diff --git a/ios/ReactTestApp.xcodeproj/project.pbxproj b/ios/ReactTestApp.xcodeproj/project.pbxproj index 2573624b4..750b3d84e 100644 --- a/ios/ReactTestApp.xcodeproj/project.pbxproj +++ b/ios/ReactTestApp.xcodeproj/project.pbxproj @@ -59,7 +59,7 @@ 19ECD0D7232ED425003D8557 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 19ECD0D9232ED425003D8557 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 19ECD0DB232ED427003D8557 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; }; - 19ECD0E3232ED427003D8557 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 19ECD0E3232ED427003D8557 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 19ECD0E8232ED427003D8557 /* ReactTestAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactTestAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 19ECD0EC232ED428003D8557 /* ReactTestAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactTestAppTests.swift; sourceTree = ""; }; 19ECD0EE232ED428003D8557 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -220,8 +220,8 @@ 19ECD0CA232ED425003D8557 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1341; - LastUpgradeCheck = 1341; + LastSwiftUpdateCheck = 1520; + LastUpgradeCheck = 1520; ORGANIZATIONNAME = Microsoft; TargetAttributes = { 19ECD0D1232ED425003D8557 = { @@ -379,7 +379,7 @@ DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = UBF8T346G9; ENABLE_PREVIEWS = YES; - INFOPLIST_FILE = ReactTestApp/Info.plist; + INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -403,7 +403,7 @@ DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = UBF8T346G9; ENABLE_PREVIEWS = YES; - INFOPLIST_FILE = ReactTestApp/Info.plist; + INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/test_app.rb b/ios/test_app.rb index 15eaea3db..fa18a6be1 100644 --- a/ios/test_app.rb +++ b/ios/test_app.rb @@ -1,3 +1,4 @@ +require('cfpropertylist') require('json') require('pathname') @@ -121,6 +122,33 @@ def generate_assets_catalog!(project_root, target_platform, destination) end end +def generate_info_plist!(project_root, target_platform, destination) + manifest = app_manifest(project_root) + return if manifest.nil? + + infoplist_src = project_path('ReactTestApp/Info.plist', target_platform) + infoplist_dst = File.join(destination, File.basename(infoplist_src)) + + plist = CFPropertyList::List.new(file: infoplist_src) + info = CFPropertyList.native_types(plist.value) + + # Register fonts + fonts = [] + resources = resolve_resources(manifest, target_platform) + resources.each do |filename| + fonts << File.basename(filename) if filename.end_with?('.otf') || filename.end_with?('.ttf') + end + unless fonts.empty? + # https://developer.apple.com/documentation/bundleresources/information_property_list/atsapplicationfontspath + info['ATSApplicationFontsPath'] = '.' if target_platform == :macos + # https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app + info['UIAppFonts'] = fonts unless target_platform == :macos + end + + plist.value = CFPropertyList.guess(info) + plist.save(infoplist_dst, CFPropertyList::List::FORMAT_XML, { :formatted => true }) +end + def react_native_pods(version) if version.zero? || version >= v(0, 71, 0) 'use_react_native-0.71' @@ -226,6 +254,7 @@ def make_project!(xcodeproj, project_root, target_platform, options) end generate_assets_catalog!(project_root, target_platform, destination) + generate_info_plist!(project_root, target_platform, destination) # Copy localization files and replace instances of `ReactTestApp` with app display name product_name = display_name || name @@ -251,13 +280,11 @@ def make_project!(xcodeproj, project_root, target_platform, options) # Note the location of Node so we can use it later in script phases File.open(File.join(project_root, '.xcode.env'), 'w') do |f| - node_bin = `which node` - node_bin.strip! + node_bin = `which node`.strip! f.write("export NODE_BINARY=#{node_bin}\n") end File.open(File.join(destination, '.env'), 'w') do |f| - node_bin = `dirname $(which node)` - node_bin.strip! + node_bin = `dirname $(which node)`.strip! f.write("export PATH=#{node_bin}:$PATH\n") end diff --git a/macos/ReactTestApp.xcodeproj/project.pbxproj b/macos/ReactTestApp.xcodeproj/project.pbxproj index b278ba53e..3a53b1a17 100644 --- a/macos/ReactTestApp.xcodeproj/project.pbxproj +++ b/macos/ReactTestApp.xcodeproj/project.pbxproj @@ -44,7 +44,7 @@ 193EF064247A736200BE8C79 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 193EF066247A736300BE8C79 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; }; 193EF069247A736300BE8C79 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 193EF06B247A736300BE8C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 193EF06B247A736300BE8C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 193EF06C247A736300BE8C79 /* ReactTestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ReactTestApp.entitlements; sourceTree = ""; }; 193EF071247A736300BE8C79 /* ReactTestAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactTestAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 193EF077247A736300BE8C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -218,8 +218,8 @@ 193EF057247A736100BE8C79 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1341; - LastUpgradeCheck = 1341; + LastSwiftUpdateCheck = 1520; + LastUpgradeCheck = 1520; ORGANIZATIONNAME = Microsoft; TargetAttributes = { 193EF05E247A736100BE8C79 = { @@ -389,7 +389,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = ReactTestApp/Info.plist; + INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -410,7 +410,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = ReactTestApp/Info.plist; + INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", diff --git a/scripts/config-plugins/plugins/withIosBaseMods.mjs b/scripts/config-plugins/plugins/withIosBaseMods.mjs index 9dceca488..ce32371e1 100644 --- a/scripts/config-plugins/plugins/withIosBaseMods.mjs +++ b/scripts/config-plugins/plugins/withIosBaseMods.mjs @@ -29,7 +29,7 @@ const defaultProviders = { expoProviders.xcodeproj, "ReactTestApp.xcodeproj/project.pbxproj" ), - infoPlist: modifyFilePath(expoProviders.infoPlist, "ReactTestApp/Info.plist"), + infoPlist: modifyFilePath(expoProviders.infoPlist, "Info.plist"), entitlements: modifyFilePath( expoProviders.entitlements, "ReactTestApp/ReactTestApp.entitlements" diff --git a/test-app.gradle b/test-app.gradle index 8a6e15e92..5b39d3deb 100644 --- a/test-app.gradle +++ b/test-app.gradle @@ -14,6 +14,11 @@ private static void applyConfigPlugins(String testAppDir, File rootDir) { } } +private static boolean isFontFile(File file) { + // https://github.com/facebook/react-native/blob/3dfedbc1aec18a4255e126fde96d5dc7b1271ea7/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/assets/ReactFontManager.java#L28 + return file.name.endsWith(".ttf") || file.name.endsWith(".otf") +} + def testAppDir = buildscript.sourceFile.getParent() apply(from: "${testAppDir}/android/test-app-util.gradle") @@ -93,17 +98,39 @@ ext.applyTestAppModule = { Project project -> def generatedResDir = file("${buildDir}/generated/rncli/src/main/res/") generatedResDir.mkdirs() + // https://github.com/facebook/react-native/blob/3dfedbc1aec18a4255e126fde96d5dc7b1271ea7/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/assets/ReactFontManager.java#L25 + def generatedFontsDir = file("${generatedAssetsDir}/fonts") + generatedFontsDir.mkdirs() + def generatedRawDir = file("${generatedResDir}/raw") generatedRawDir.mkdirs() preBuild.dependsOn(tasks.register("copyAssets", Copy) { androidResourceFiles.each { - from(it) + if (!isFontFile(it)) { + from(it) + } } into(generatedAssetsDir) }) + preBuild.dependsOn(tasks.register("copyFonts", Copy) { + androidResourceFiles.each { + if (isFontFile(it)) { + from(it) { + // File-based resource names must contain only lowercase + // a-z, 0-9, or underscore + rename { + it.toLowerCase() + } + } + } + } + + into(generatedFontsDir) + }) + preBuild.dependsOn(tasks.register("copyResources", Copy) { if (androidResDir != null) { from(androidResDir)