android-dev-build (#8352)

* improve resource finding procedure and add android-dev-build

Added the `android-dev-build` profile to trigger building a developer
apk.

Developer apk is at application id forge.app.dev, and has name
'Forge (dev)'. It is installable in parallel with the official release
app allowing developers to test the android build on their phones
without interfering with their existing installation.

Updated how android resources are found to accomodate changes in
application id at runtime. This method doesn't rely on the 'R' package.

* Use all arguments of getIdentifier

Use all arguments of getIdentifier instead of using a fully qualified
resource name
This commit is contained in:
Matthew Scott Krafczyk
2025-08-14 11:06:54 -05:00
committed by GitHub
parent 0767eb03e0
commit f4f8ee9cb6
2 changed files with 163 additions and 6 deletions

View File

@@ -694,5 +694,136 @@
</plugins>
</build>
</profile>
<profile>
<!-- test build signed with embedded debug.keystore from uber-signer -->
<id>android-dev-build</id>
<properties>
<app.id.dev>forge.app.dev</app.id.dev>
<packaging.type>apk</packaging.type>
</properties>
<build>
<!-- append generated snapshot-version property -->
<finalName>forge-dev-android-${snapshot-version}</finalName>
<plugins>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<version>3.4.1</version>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<id>SignV2</id>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<workingDirectory>${pom.basedir}</workingDirectory>
<executable>java</executable>
<arguments>
<argument>-jar</argument>
<argument>${pom.basedir}/tools/uber-apk-signer.jar</argument>
<argument>-a</argument>
<argument>${pom.basedir}/target/</argument>
<argument>--debug</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<groupId>com.simpligility.maven.plugins</groupId>
<artifactId>android-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.4</version>
</dependency>
<dependency>
<groupId>sun</groupId>
<artifactId>misc</artifactId>
<version>1</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/sun-misc.jar</systemPath>
</dependency>
</dependencies>
<version>4.6.2</version>
<extensions>true</extensions>
<configuration>
<sign>
<debug>false</debug>
</sign>
<renameManifestPackage>${app.id.dev}</renameManifestPackage>
<sdk>
<platform>${androidPlatform}</platform>
<buildTools>${androidBuildTools}</buildTools>
</sdk>
<zipalign>
<verbose>false</verbose>
</zipalign>
<dexForceJumbo>true</dexForceJumbo>
<assetsDirectory>${project.basedir}/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/res</resourceDirectory>
<nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory>
<extractDuplicates>true</extractDuplicates>
<proguard>
<skip>false</skip>
<config>${project.basedir}/proguard.cfg</config>
</proguard>
<proguardProguardJarPath>${pom.basedir}/tools/proguard.jar</proguardProguardJarPath>
<release>true</release>
<dexCompiler>d8</dexCompiler>
<d8>
<minApi>26</minApi>
<jvmArguments>
<argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument>
</jvmArguments>
</d8>
<dex>
<multi-dex>true</multi-dex>
<jvmArguments>
<argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument>
</jvmArguments>
<dexArguments>--min-sdk-version=26</dexArguments>
</dex>
</configuration>
<executions>
<execution>
<id>update-manifest</id>
<goals>
<goal>manifest-merger</goal>
</goals>
<configuration>
<manifestVersionName>${snapshot-version}-dev</manifestVersionName>
</configuration>
</execution>
<execution>
<id>fix-provider-authorities</id>
<phase>process-resources</phase>
<goals>
<goal>manifest-update</goal>
</goals>
<configuration>
<versionCodeUpdateFromVersion>false</versionCodeUpdateFromVersion>
<manifestApplicationLabel>Forge (dev)</manifestApplicationLabel>
<manifestProviderAuthorities>
<io.sentry.android.core.SentryInitProvider>${app.id.dev}.SentryInitProvider</io.sentry.android.core.SentryInitProvider>
<io.sentry.android.core.SentryPerformanceProvider>${app.id.dev}.SentryPerformanceProvider</io.sentry.android.core.SentryPerformanceProvider>
<de.cketti.fileprovider.PublicFileProvider>${app.id.dev}.publicfileprovider</de.cketti.fileprovider.PublicFileProvider>
</manifestProviderAuthorities>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -90,6 +90,26 @@ public class Main extends AndroidApplication {
private TextView progressText;
private String versionString;
// The package name the resources are compiled under (stable across dev/prod).
// If you ever change the base app package, update this constant once.
private static final String RES_PKG_FALLBACK = "forge.app";
private int resId(String type, String name) {
// 1) Try fully-qualified with *runtime* package
int id = getResources().getIdentifier(name, type, getPackageName());
if (id != 0) return id;
// 2) Try fully-qualified with *fallback* resource package
if (!RES_PKG_FALLBACK.equals(getPackageName())) {
id = getResources().getIdentifier(name, type, RES_PKG_FALLBACK);
if (id != 0) return id;
}
android.util.Log.e("ForgeRes", "Missing resource " + type + "/" + name +
" for pkg=" + getPackageName() + " (also tried " + RES_PKG_FALLBACK + ")");
return 0;
}
private AndroidClipboard getAndroidClipboard() {
if (androidClipboard == null)
androidClipboard = new AndroidClipboard();
@@ -148,13 +168,13 @@ public class Main extends AndroidApplication {
} catch (Exception e) {
versionString = "0.0";
}
setContentView(getResources().getIdentifier("main", "layout", getPackageName()));
setContentView(resId("layout", "main"));
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
sharedPreferences = getPreferences(Context.MODE_PRIVATE);
progressBar = findViewById(getResources().getIdentifier("pBar", "id", getPackageName()));
progressBar = findViewById(resId("id", "pBar"));
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.GONE);
progressText = findViewById(getResources().getIdentifier("pText", "id", getPackageName()));
progressText = findViewById(resId("id", "pText"));
progressText.setVisibility(View.GONE);
isMIUI = isMiUi();
@@ -308,8 +328,8 @@ public class Main extends AndroidApplication {
private void loadGame(final String title, final String steps, boolean isLandscape, AndroidAdapter adapter, boolean permissiongranted, int totalRAM, boolean isTabletDevice, AndroidApplicationConfiguration config, boolean exception, String msg) {
try {
final Handler handler = new Handler();
forgeLogo = findViewById(getResources().getIdentifier("logo_id", "id", getPackageName()));
activeView = findViewById(getResources().getIdentifier("mainview", "id", getPackageName()));
forgeLogo = findViewById(resId("id", "logo_id"));
activeView = findViewById(resId("id", "mainview"));
activeView.setBackgroundColor(Color.WHITE);
forgeView = initializeForView(Forge.getApp(getAndroidClipboard(), adapter, ASSETS_DIR, false, !isLandscape, totalRAM, isTabletDevice, Build.VERSION.SDK_INT, Build.VERSION.RELEASE, getDeviceName()), config);
@@ -674,6 +694,11 @@ public class Main extends AndroidApplication {
return new GitLogs().getLatestReleaseTag(releaseAtom);
}
private String fileProviderAuthority() {
// Works for both prod (forge.app) and dev (forge.app.dev)
return getPackageName() + ".publicfileprovider";
}
@Override
public boolean openFile(String filename) {
try {
@@ -688,7 +713,8 @@ public class Main extends AndroidApplication {
return true;
} else {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(PublicFileProvider.getUriForFile(getContext(), "com.mydomain.publicfileprovider", new File(filename)));
intent.setData(PublicFileProvider.getUriForFile(
getContext(), fileProviderAuthority(), new File(filename)));
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
return true;