Created
March 1, 2023 17:53
-
-
Save planetis-m/a437db724185215910a59c3b31d1cdf4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os, enum, shutil, subprocess | |
class CpuPlatform(enum.Enum): | |
arm = 1 | |
arm64 = 2 | |
i386 = 3 | |
amd64 = 4 | |
class DeviceOrientation(enum.Enum): | |
portrait = 1 | |
landscape = 2 | |
sensor = 3 | |
def toArchName(x): | |
match x: | |
case CpuPlatform.arm: | |
return "armeabi-v7a" | |
case CpuPlatform.arm64: | |
return "arm64-v8a" | |
case CpuPlatform.i386: | |
return "x86" | |
case CpuPlatform.amd64: | |
return "x86_64" | |
# Define Android architecture (armeabi-v7a, arm64-v8a, x86, x86-64) and API version | |
AndroidApiVersion = 29 | |
AndroidCPUs = [CpuPlatform.arm64] | |
# Required path variables | |
JavaHome = "/usr/lib/jvm/java-19-openjdk" | |
AndroidNdk = "/opt/android-ndk" | |
AndroidHome = "/opt/android-sdk" | |
AndroidBuildTools = os.path.join(AndroidHome, "build-tools/33.0.1") | |
AndroidPlatformTools = os.path.join(AndroidHome, "platform-tools") | |
# Android project configuration variables | |
ProjectName = "raylib_game" | |
ProjectLibraryName = "main" | |
ProjectBuildId = "android" | |
ProjectBuildPath = ProjectBuildId + "." + ProjectName | |
ProjectResourcesPath = "src/resources" | |
ProjectSourceFile = "src/raylib_game.nim" | |
# Android app configuration variables | |
AppLabelName = "rGame" | |
AppCompanyName = "raylib" | |
AppProductName = "rgame" | |
AppVersionCode = 1 | |
AppVersionName = "1.0" | |
AppIconLdpi = "logo/raylib_36x36.png" | |
AppIconMdpi = "logo/raylib_48x48.png" | |
AppIconHdpi = "logo/raylib_72x72.png" | |
AppScreenOrientation = DeviceOrientation.landscape | |
AppKeystorePass = "raylib" | |
def setupAndroid(): | |
# Create required temp directories for APK building | |
os.makedirs(os.path.join(ProjectBuildPath, "src", "com", AppCompanyName, AppProductName), exist_ok=True) | |
for cpu in AndroidCPUs: | |
os.makedirs(os.path.join(ProjectBuildPath, "lib", toArchName(cpu)), exist_ok=True) | |
os.makedirs(os.path.join(ProjectBuildPath, "bin"), exist_ok=True) | |
os.makedirs(os.path.join(ProjectBuildPath, "res", "drawable-ldpi"), exist_ok=True) | |
os.makedirs(os.path.join(ProjectBuildPath, "res", "drawable-mdpi"), exist_ok=True) | |
os.makedirs(os.path.join(ProjectBuildPath, "res", "drawable-hdpi"), exist_ok=True) | |
os.makedirs(os.path.join(ProjectBuildPath, "res", "values"), exist_ok=True) | |
# os.makedirs(os.path.join(ProjectBuildPath, "assets", "resources"), exist_ok=True) | |
os.makedirs(os.path.join(ProjectBuildPath, "obj", "screens"), exist_ok=True) | |
# Copy project required resources: strings.xml, icon.png, assets | |
with open(os.path.join(ProjectBuildPath, "res", "values", "strings.xml"), "w") as f: | |
f.write("""<?xml version='1.0' encoding='utf-8'?>\n<resources><string name='app_name'>{}</string></resources>\n""".format(AppLabelName)) | |
shutil.copy2(AppIconLdpi, os.path.join(ProjectBuildPath, "res", "drawable-ldpi", "icon.png")) | |
shutil.copy2(AppIconMdpi, os.path.join(ProjectBuildPath, "res", "drawable-mdpi", "icon.png")) | |
shutil.copy2(AppIconHdpi, os.path.join(ProjectBuildPath, "res", "drawable-hdpi", "icon.png")) | |
shutil.copytree(ProjectResourcesPath, os.path.join(ProjectBuildPath, "assets", "resources")) | |
# Generate NativeLoader.java to load required shared libraries | |
with open(os.path.join(ProjectBuildPath, "src", "com", AppCompanyName, AppProductName, "NativeLoader.java"), "w") as f: | |
f.write("""package com.{}.{}; | |
public class NativeLoader extends android.app.NativeActivity {{ | |
static {{ | |
System.loadLibrary("{}"); | |
}} | |
}} | |
""".format(AppCompanyName, AppProductName, ProjectLibraryName)) | |
# Generate AndroidManifest.xml with all the required options | |
with open(os.path.join(ProjectBuildPath, "AndroidManifest.xml"), "w") as f: | |
f.write("""<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.{}.{}" | |
android:versionCode="{}" android:versionName="{}" > | |
<uses-sdk android:minSdkVersion="{}" /> | |
<uses-feature android:glEsVersion="0x00020000" android:required="true" /> | |
<application android:allowBackup="false" android:label="@string/app_name" android:icon="@drawable/icon" > | |
<activity android:name="com.{}.{}.NativeLoader" | |
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" | |
android:configChanges="orientation|keyboardHidden|screenSize" | |
android:screenOrientation="{}" android:launchMode="singleTask" | |
android:clearTaskOnLaunch="true"> | |
<meta-data android:name="android.app.lib_name" android:value="{}" /> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
</application> | |
</manifest> | |
""".format(AppCompanyName, AppProductName, AppVersionCode, AppVersionName, AndroidApiVersion, AppCompanyName, AppProductName, AppScreenOrientation, ProjectLibraryName)) | |
def buildAndroid(): | |
androidResourcePath = os.path.join(AndroidHome, "platforms/android-{}/android.jar".format(AndroidApiVersion)) | |
subprocess.run([os.path.join(AndroidBuildTools, "aapt"), "package", "-f", "-m", "-S", os.path.join(ProjectBuildPath, "res"), | |
"-J", os.path.join(ProjectBuildPath, "src"), "-M", os.path.join(ProjectBuildPath, "AndroidManifest.xml"), | |
"-I", androidResourcePath]) | |
for cpu in AndroidCPUs: | |
subprocess.run(["nim", "c", "-d:release", "--os:android", "--cpu:{}".format(cpu), "-d:AndroidApiVersion={}".format(AndroidApiVersion), | |
"-d:AndroidNdk={}".format(AndroidNdk), "-o:{}".format(os.path.join(ProjectBuildPath, "lib", toArchName(cpu), "lib{}.so".format(ProjectLibraryName))), | |
"--nimcache:{}".format(os.path.join("~/.cache/nim", "{}_{}".format(ProjectName, cpu))), | |
ProjectSourceFile]) | |
subprocess.run([os.path.join(JavaHome, "bin/javac"), "-verbose", "-source", "1.8", "-target", "1.8", "-d", os.path.join(ProjectBuildPath, "obj"), | |
"-bootclasspath", os.path.join(JavaHome, "jre/lib/rt.jar"), "-classpath", "{}:{}".format(androidResourcePath, os.path.join(ProjectBuildPath, "obj")), | |
"-sourcepath", os.path.join(ProjectBuildPath, "src"), os.path.join(ProjectBuildPath, "src/com", AppCompanyName, AppProductName, "R.java"), | |
os.path.join(ProjectBuildPath, "src/com", AppCompanyName, AppProductName, "NativeLoader.java")]) | |
classes = [] | |
for f in os.listdir(os.path.join(ProjectBuildPath, "obj/com", AppCompanyName, AppProductName)): | |
if f.endswith(".class"): | |
classes.append(f) | |
subprocess.run([os.path.join(AndroidBuildTools, "d8"), "--release", "--output", os.path.join(ProjectBuildPath, "bin"), | |
" ".join(classes), "--lib", androidResourcePath]) | |
unsignedApkPath = os.path.join(ProjectBuildPath, "bin", "{}.unsigned.apk".format(ProjectName)) | |
signed_apk_path = os.path.join(ProjectBuildPath, "bin", "{}.signed.apk".format(ProjectName)) | |
os.remove(unsignedApkPath) # fixes rebuilding | |
os.remove(signedApkPath) | |
os.system(f'{AndroidBuildTools}/aapt package -f -M {ProjectBuildPath}/AndroidManifest.xml -S {ProjectBuildPath}/res -A {ProjectBuildPath}/assets -I {androidResourcePath} -F {unsignedApkPath} {ProjectBuildPath}/bin') | |
setupAndroid() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment