Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for custom app fonts #1828

Merged
merged 5 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 5 additions & 5 deletions ios/ReactTestApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
19ECD0D7232ED425003D8557 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
19ECD0D9232ED425003D8557 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
19ECD0EE232ED428003D8557 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -220,8 +220,8 @@
19ECD0CA232ED425003D8557 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1341;
LastUpgradeCheck = 1341;
LastSwiftUpdateCheck = 1520;
LastUpgradeCheck = 1520;
ORGANIZATIONNAME = Microsoft;
TargetAttributes = {
19ECD0D1232ED425003D8557 = {
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down
36 changes: 32 additions & 4 deletions ios/test_app.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require('cfpropertylist')
require('json')
require('pathname')

Expand Down Expand Up @@ -121,6 +122,34 @@ 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
font_files = ['.otf', '.ttf']
fonts = []
resources = resolve_resources(manifest, target_platform)
resources.each do |filename|
fonts << File.basename(filename) if font_files.include?(File.extname(filename))
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'
Expand Down Expand Up @@ -226,6 +255,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
Expand All @@ -251,13 +281,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

Expand Down
10 changes: 5 additions & 5 deletions macos/ReactTestApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
193EF064247A736200BE8C79 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
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 = "<group>"; };
193EF06B247A736300BE8C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
Expand Down Expand Up @@ -218,8 +218,8 @@
193EF057247A736100BE8C79 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1341;
LastUpgradeCheck = 1341;
LastSwiftUpdateCheck = 1520;
LastUpgradeCheck = 1520;
ORGANIZATIONNAME = Microsoft;
TargetAttributes = {
193EF05E247A736100BE8C79 = {
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion scripts/config-plugins/plugins/withIosBaseMods.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
64 changes: 63 additions & 1 deletion test-app.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,36 @@ 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 [".otf", ".ttf"].any { file.name.endsWith(it) }
}

private static boolean isMediaFile(File file) {
// https://developer.android.com/media/platform/supported-formats
return [
".3gp",
".aac",
".amr",
".flac",
".imy",
".m4a",
".mid",
".mkv",
".mp3",
".mp4",
".mxmf",
".ogg",
".ota",
".rtttl",
".rtx",
".ts",
".wav",
".webm",
".xmf",
].any { file.name.endsWith(it) }
}

def testAppDir = buildscript.sourceFile.getParent()
apply(from: "${testAppDir}/android/test-app-util.gradle")

Expand Down Expand Up @@ -93,17 +123,49 @@ 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) && !isMediaFile(it)) {
from(it)
}
}

into(generatedAssetsDir)
})

preBuild.dependsOn(tasks.register("copyFonts", Copy) {
androidResourceFiles.each {
if (isFontFile(it)) {
from(it)
}
}

into(generatedFontsDir)
})

preBuild.dependsOn(tasks.register("copyRawResources", Copy) {
androidResourceFiles.each {
if (isMediaFile(it)) {
from(it) {
// File-based resource names must contain only lowercase
// a-z, 0-9, or underscore
rename {
it.toLowerCase()
}
}
}
}

into(generatedRawDir)
})

preBuild.dependsOn(tasks.register("copyResources", Copy) {
if (androidResDir != null) {
from(androidResDir)
Expand Down
Loading