Split the Android platform java logic into an Android library module (lib) and an application module (app).

The application module `app` serves double duties of providing the prebuilt Godot binaries ('android_debug.apk', 'android_release.apk') and the Godot custom build template ('android_source.zip').
This commit is contained in:
fhuya 2019-09-02 17:31:51 -07:00
parent ba854bbc7b
commit 7fabfd402f
141 changed files with 386 additions and 282 deletions

View file

@ -562,10 +562,8 @@ bool ExportTemplateManager::can_install_android_template() {
Error ExportTemplateManager::install_android_template() {
// To support custom Android builds, we install various things to the project's res://android folder.
// First is the Java source code and buildsystem from android_source.zip.
// Then we extract the Godot Android libraries from pre-build android_release.apk
// and android_debug.apk, to place them in the libs folder.
// To support custom Android builds, we install the Java source code and buildsystem
// from android_source.zip to the project's res://android folder.
DirAccessRef da = DirAccess::open("res://");
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
@ -661,89 +659,6 @@ Error ExportTemplateManager::install_android_template() {
ProgressDialog::get_singleton()->end_task("uncompress_src");
unzClose(pkg);
// Extract libs from pre-built APKs.
err = _extract_libs_from_apk("release");
ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_release.apk.");
err = _extract_libs_from_apk("debug");
ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_debug.apk.");
return OK;
}
Error ExportTemplateManager::_extract_libs_from_apk(const String &p_target_name) {
const String &templates_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG);
const String &apk_file = templates_path.plus_file("android_" + p_target_name + ".apk");
ERR_FAIL_COND_V(!FileAccess::exists(apk_file), ERR_CANT_OPEN);
FileAccess *src_f = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(apk_file.utf8().get_data(), &io);
ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android APK can't be extracted.");
DirAccessRef da = DirAccess::open("res://");
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
// 8 steps because 4 arches, 2 libs per arch.
ProgressDialog::get_singleton()->add_task("extract_libs_from_apk", TTR("Extracting Android Libraries From APKs"), 8);
int ret = unzGoToFirstFile(pkg);
Set<String> dirs_tested;
int idx = 0;
while (ret == UNZ_OK) {
// Get file path.
unz_file_info info;
char fpath[16384];
ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0);
String path = fpath;
String base_dir = path.get_base_dir();
String file = path.get_file();
if (!base_dir.begins_with("lib") || path.ends_with("/")) {
ret = unzGoToNextFile(pkg);
continue;
}
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
// Read.
unzOpenCurrentFile(pkg);
unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
// We have a "lib" folder in the APK, but it should be "libs/{release,debug}" in the source dir.
String target_base_dir = base_dir.replace_first("lib", String("libs").plus_file(p_target_name));
if (!dirs_tested.has(base_dir)) {
da->make_dir_recursive(String("android/build").plus_file(target_base_dir));
dirs_tested.insert(base_dir);
}
String to_write = String("res://android/build").plus_file(target_base_dir.plus_file(path.get_file()));
FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE);
if (f) {
f->store_buffer(data.ptr(), data.size());
memdelete(f);
#ifndef WINDOWS_ENABLED
// We can't retrieve Unix permissions from the APK it seems, so simply set 0755 as should be.
FileAccess::set_unix_permissions(to_write, 0755);
#endif
} else {
ERR_PRINTS("Can't uncompress file: " + to_write);
}
ProgressDialog::get_singleton()->task_step("extract_libs_from_apk", path, idx);
idx++;
ret = unzGoToNextFile(pkg);
}
ProgressDialog::get_singleton()->end_task("extract_libs_from_apk");
unzClose(pkg);
return OK;
}

View file

@ -72,8 +72,6 @@ class ExportTemplateManager : public ConfirmationDialog {
virtual void ok_pressed();
bool _install_from_file(const String &p_file, bool p_use_progress = true);
Error _extract_libs_from_apk(const String &p_target_name);
void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data);
void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data);

View file

@ -86,7 +86,7 @@ do
if grep -q "thirdparty" <<< $file; then
continue;
fi
if grep -q "platform/android/java/src/com" <<< $file; then
if grep -q "platform/android/java/lib/src/com" <<< $file; then
continue;
fi

View file

@ -11,7 +11,7 @@ else
RANGE=HEAD
fi
FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -v platform/android/java/src/com/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$")
FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -v platform/android/java/lib/src/com/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$")
echo "Checking files:\n$FILES"
# create a random filename to store our generated patch

View file

@ -18,7 +18,7 @@ android_arch_dirs = {
def get_android_out_dir(env):
return os.path.join(Dir('#platform/android/java/libs').abspath,
return os.path.join(Dir('#platform/android/java/lib/libs').abspath,
'release' if env['target'] == 'release' else 'debug',
android_arch_dirs[env['android_arch']])

View file

@ -50,30 +50,8 @@ if lib_arch_dir != '':
else: # release_debug, debug
lib_type_dir = 'debug'
out_dir = '#platform/android/java/libs/' + lib_type_dir + '/' + lib_arch_dir
out_dir = '#platform/android/java/lib/libs/' + lib_type_dir + '/' + lib_arch_dir
env_android.Command(out_dir + '/libgodot_android.so', '#bin/libgodot' + env['SHLIBSUFFIX'], Move("$TARGET", "$SOURCE"))
stl_lib_path = str(env['ANDROID_NDK_ROOT']) + '/sources/cxx-stl/llvm-libc++/libs/' + lib_arch_dir + '/libc++_shared.so'
env_android.Command(out_dir + '/libc++_shared.so', stl_lib_path, Copy("$TARGET", "$SOURCE"))
# Zip android/java folder for the source export template.
print("Archiving platform/android/java as bin/android_source.zip...")
import os
import zipfile
# Change dir to avoid have zipped paths start from the android/java folder.
olddir = os.getcwd()
os.chdir(Dir('#platform/android/java').abspath)
bindir = Dir('#bin').abspath
# Make 'bin' dir if missing, can happen on fresh clone.
if not os.path.exists(bindir):
os.makedirs(bindir)
zipf = zipfile.ZipFile(os.path.join(bindir, 'android_source.zip'), 'w', zipfile.ZIP_DEFLATED)
exclude_dirs = ['.gradle', 'build', 'libs', 'patches']
for root, dirs, files in os.walk('.', topdown=True):
# Change 'dirs' in place to exclude folders we don't want.
# https://stackoverflow.com/a/19859907
dirs[:] = [d for d in dirs if d not in exclude_dirs]
for f in files:
zipf.write(os.path.join(root, f))
zipf.close()
os.chdir(olddir)

View file

@ -794,6 +794,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
string_table.write[attr_value] = version_name;
}
if (tname == "instrumentation" && attrname == "targetPackage") {
string_table.write[attr_value] = get_package_name(package_name);
}
if (tname == "activity" && attrname == "screenOrientation") {
encode_uint32(orientation == 0 ? 0 : 1, &p_manifest.write[iofs + 16]);

View file

@ -41,7 +41,7 @@
android:value="xr_mode_metadata_value" />
<activity
android:name="org.godotengine.godot.Godot"
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
@ -56,18 +56,10 @@
</intent-filter>
</activity>
<service android:name="org.godotengine.godot.GodotDownloaderService" />
<!-- Custom application XML added by add-ons. -->
<!--CHUNK_APPLICATION_BEGIN-->
<!--CHUNK_APPLICATION_END-->
</application>
<instrumentation
android:icon="@drawable/icon"
android:label="@string/godot_project_name_string"
android:name="org.godotengine.godot.GodotInstrumentation"
android:targetPackage="org.godotengine.game" />
</manifest>

View file

@ -0,0 +1,121 @@
// Gradle build config for Godot Engine's Android port.
//
// Do not remove/modify comments ending with BEGIN/END, they are used to inject
// addon-specific configuration.
apply from: 'config.gradle'
buildscript {
apply from: 'config.gradle'
repositories {
google()
jcenter()
//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN
//CHUNK_BUILDSCRIPT_REPOSITORIES_END
}
dependencies {
classpath libraries.androidGradlePlugin
//CHUNK_BUILDSCRIPT_DEPENDENCIES_BEGIN
//CHUNK_BUILDSCRIPT_DEPENDENCIES_END
}
}
apply plugin: 'com.android.application'
allprojects {
repositories {
mavenCentral()
google()
jcenter()
//CHUNK_ALLPROJECTS_REPOSITORIES_BEGIN
//CHUNK_ALLPROJECTS_REPOSITORIES_END
}
}
dependencies {
if (rootProject.findProject(":lib")) {
implementation project(":lib")
} else {
// Custom build mode. In this scenario this project is the only one around and the Godot
// library is available through the pre-generated godot-lib.*.aar android archive files.
debugImplementation fileTree(dir: 'libs/debug', include: ['*.jar', '*.aar'])
releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar'])
}
//CHUNK_DEPENDENCIES_BEGIN
//CHUNK_DEPENDENCIES_END
}
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
// Feel free to modify the application id to your own.
applicationId "com.godot.game"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN
//CHUNK_ANDROID_DEFAULTCONFIG_END
}
lintOptions {
abortOnError false
disable 'MissingTranslation', 'UnusedResources'
}
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}
// Both signing and zip-aligning will be done at export time
buildTypes.all { buildType ->
buildType.zipAlignEnabled false
buildType.signingConfig null
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [
'src'
//DIR_SRC_BEGIN
//DIR_SRC_END
]
res.srcDirs = [
'res'
//DIR_RES_BEGIN
//DIR_RES_END
]
aidl.srcDirs = [
'aidl'
//DIR_AIDL_BEGIN
//DIR_AIDL_END
]
assets.srcDirs = [
'assets'
//DIR_ASSETS_BEGIN
//DIR_ASSETS_END
]
}
debug.jniLibs.srcDirs = [
'libs/debug'
//DIR_JNI_DEBUG_BEGIN
//DIR_JNI_DEBUG_END
]
release.jniLibs.srcDirs = [
'libs/release'
//DIR_JNI_RELEASE_BEGIN
//DIR_JNI_RELEASE_END
]
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
output.outputFileName = "android_${variant.name}.apk"
}
}
}
//CHUNK_GLOBAL_BEGIN
//CHUNK_GLOBAL_END

View file

@ -0,0 +1,12 @@
ext.versions = [
androidGradlePlugin : '3.4.2',
compileSdk : 28,
minSdk : 18,
targetSdk : 28,
buildTools : '28.0.3',
]
ext.libraries = [
androidGradlePlugin : "com.android.tools.build:gradle:$versions.androidGradlePlugin"
]

View file

@ -0,0 +1,10 @@
package com.godot.game;
import org.godotengine.godot.Godot;
/**
* Template activity for Godot Android custom builds.
* Feel free to extend and modify this class for your custom logic.
*/
public class GodotApp extends Godot {
}

View file

@ -1,111 +1,95 @@
// Gradle build config for Godot Engine's Android port.
//
// Do not remove/modify comments ending with BEGIN/END, they are used to inject
// addon-specific configuration.
apply from: 'app/config.gradle'
buildscript {
apply from: 'app/config.gradle'
repositories {
google()
jcenter()
//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN
//CHUNK_BUILDSCRIPT_REPOSITORIES_END
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
//CHUNK_BUILDSCRIPT_DEPENDENCIES_BEGIN
//CHUNK_BUILDSCRIPT_DEPENDENCIES_END
classpath libraries.androidGradlePlugin
}
}
apply plugin: 'com.android.application'
allprojects {
repositories {
mavenCentral()
google()
jcenter()
//CHUNK_ALLPROJECTS_REPOSITORIES_BEGIN
//CHUNK_ALLPROJECTS_REPOSITORIES_END
mavenCentral()
}
}
dependencies {
implementation "com.android.support:support-core-utils:28.0.0"
//CHUNK_DEPENDENCIES_BEGIN
//CHUNK_DEPENDENCIES_END
def binDir = "../../../bin/"
/**
* Copy the generated 'android_debug.apk' binary template into the Godot bin directory.
* Depends on the app build task to ensure the binary is generated prior to copying.
*/
task copyDebugBinaryToBin(type: Copy) {
dependsOn ':app:build'
from('app/build/outputs/apk/debug')
into(binDir)
include('android_debug.apk')
}
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
useLibrary 'org.apache.http.legacy'
defaultConfig {
minSdkVersion 18
targetSdkVersion 28
//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN
//CHUNK_ANDROID_DEFAULTCONFIG_END
}
lintOptions {
abortOnError false
disable 'MissingTranslation', 'UnusedResources'
}
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}
// Both signing and zip-aligning will be done at export time
buildTypes.all { buildType ->
buildType.zipAlignEnabled false
buildType.signingConfig null
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [
'src'
//DIR_SRC_BEGIN
//DIR_SRC_END
]
res.srcDirs = [
'res'
//DIR_RES_BEGIN
//DIR_RES_END
]
aidl.srcDirs = [
'aidl'
//DIR_AIDL_BEGIN
//DIR_AIDL_END
]
assets.srcDirs = [
'assets'
//DIR_ASSETS_BEGIN
//DIR_ASSETS_END
]
}
debug.jniLibs.srcDirs = [
'libs/debug'
//DIR_JNI_DEBUG_BEGIN
//DIR_JNI_DEBUG_END
]
release.jniLibs.srcDirs = [
'libs/release'
//DIR_JNI_RELEASE_BEGIN
//DIR_JNI_RELEASE_END
]
}
// No longer used, as it's not useful for build source template
//applicationVariants.all { variant ->
// variant.outputs.all { output ->
// output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk"
// }
//}
/**
* Copy the generated 'android_release.apk' binary template into the Godot bin directory.
* Depends on the app build task to ensure the binary is generated prior to copying.
*/
task copyReleaseBinaryToBin(type: Copy) {
dependsOn ':app:build'
from('app/build/outputs/apk/release')
into(binDir)
include('android_release.apk')
}
//CHUNK_GLOBAL_BEGIN
//CHUNK_GLOBAL_END
/**
* Copy the Godot android library archive debug file into the app debug libs directory.
* Depends on the library build task to ensure the AAR file is generated prior to copying.
*/
task copyDebugAAR(type: Copy) {
dependsOn ':lib:build'
from('lib/build/outputs/aar')
into('app/libs/debug')
include('godot-lib.debug.aar')
}
/**
* Copy the Godot android library archive release file into the app release libs directory.
* Depends on the library build task to ensure the AAR file is generated prior to copying.
*/
task copyReleaseAAR(type: Copy) {
dependsOn ':lib:build'
from('lib/build/outputs/aar')
into('app/libs/release')
include('godot-lib.release.aar')
}
/**
* Generate Godot custom build template by zipping the source files from the app directory, as well
* as the AAR files generated by 'copyDebugAAR' and 'copyReleaseAAR'.
* The zip file also includes some gradle tools to allow building of the custom build.
*/
task zipCustomBuild(type: Zip) {
dependsOn 'copyDebugAAR'
dependsOn 'copyReleaseAAR'
from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradle.properties','gradlew', 'gradlew.bat', 'gradle/**']))
include '**/*'
archiveName 'android_source.zip'
destinationDir(file(binDir))
}
/**
* Master task used to coordinate the tasks defined above to generate the set of Godot templates.
*/
task generateGodotTemplates(type: GradleBuild) {
tasks = [
// Copy the generated aar library files to the custom build directory.
'copyDebugAAR', 'copyReleaseAAR',
// Zip the custom build directory.
'zipCustomBuild',
// Copy the prebuilt binary templates to the bin directory.
'copyDebugBinaryToBin', 'copyReleaseBinaryToBin',
]
}

View file

@ -1,5 +1,6 @@
#Mon Sep 02 02:44:30 PDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.godotengine.godot"
android:versionCode="1"
android:versionName="1.0">
<application>
<service android:name=".GodotDownloaderService" />
</application>
<instrumentation
android:icon="@drawable/icon"
android:label="@string/godot_project_name_string"
android:name=".GodotInstrumentation"
android:targetPackage="org.godotengine.godot" />
</manifest>

View file

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.6)
project(godot)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(GODOT_ROOT_DIR ../../../..)
# Get sources
file(GLOB_RECURSE SOURCES ${GODOT_ROOT_DIR}/*.c**)
file(GLOB_RECURSE HEADERS ${GODOT_ROOT_DIR}/*.h**)
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME}
SYSTEM PUBLIC
${GODOT_ROOT_DIR}
${GODOT_ROOT_DIR}/modules/gdnative/include)

View file

@ -0,0 +1,91 @@
apply plugin: 'com.android.library'
dependencies {
implementation "com.android.support:support-core-utils:28.0.0"
}
def pathToRootDir = "../../../../"
// Note: Only keep the abis you support to speed up the gradle 'assemble' task.
def supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
useLibrary 'org.apache.http.legacy'
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
}
lintOptions {
abortOnError false
disable 'MissingTranslation', 'UnusedResources'
}
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
aidl.srcDirs = ['aidl']
assets.srcDirs = ['assets']
}
debug.jniLibs.srcDirs = ['libs/debug']
release.jniLibs.srcDirs = ['libs/release']
}
libraryVariants.all { variant ->
variant.outputs.all { output ->
output.outputFileName = "godot-lib.${variant.name}.aar"
}
def buildType = variant.buildType.name.capitalize()
def taskPrefix = ""
if (project.path != ":") {
taskPrefix = project.path + ":"
}
// Disable the externalNativeBuild* task as it would cause build failures since the cmake build
// files is only setup for editing support.
gradle.startParameter.excludedTaskNames += taskPrefix + "externalNativeBuild" + buildType
// Create tasks to generate the Godot native libraries.
def taskName = "compileGodotNativeLibs" + buildType
def releaseTarget = "release"
if (buildType == "Debug") {
releaseTarget += "_debug"
}
def abiTaskNames = []
// Creating gradle tasks to generate the native libraries for the supported abis.
supportedAbis.each { abi ->
def abiTaskName = taskName + abi.capitalize()
abiTaskNames += abiTaskName
tasks.create(name: abiTaskName, type: Exec) {
executable "scons"
args "--directory=${pathToRootDir}", "platform=android", "target=${releaseTarget}", "android_arch=${abi}"
}
}
// Creating gradle task to run all of the previously generated tasks.
tasks.create(name: taskName, type: GradleBuild) {
tasks = abiTaskNames
}
// Schedule the tasks so the generated libs are present before the aar file is packaged.
tasks["merge${buildType}JniLibFolders"].dependsOn taskName
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}

View file

@ -175,7 +175,7 @@ index e4b1b0f1c..36cd6aacf 100644
-import com.android.vending.expansion.downloader.R;
+// -- GODOT start --
+//import com.android.vending.expansion.downloader.R;
+import com.godot.game.R;
+import org.godotengine.godot.R;
+// -- GODOT end --
import java.io.File;
@ -250,7 +250,7 @@ index f1536e80e..4b214b22d 100644
-import com.android.vending.expansion.downloader.R;
+// -- GODOT start --
+//import com.android.vending.expansion.downloader.R;
+import com.godot.game.R;
+import org.godotengine.godot.R;
+// -- GODOT end --
+
import com.google.android.vending.expansion.downloader.DownloadProgressInfo;

View file

@ -21,7 +21,7 @@ index a0d2779af..a8bf65f9c 100644
*/
+// -- GODOT start --
+import com.godot.game.BuildConfig;
import org.godotengine.godot.BuildConfig;
+// -- GODOT end --
+
/**

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

@ -26,7 +26,7 @@ import android.util.Log;
// -- GODOT start --
//import com.android.vending.expansion.downloader.R;
import com.godot.game.R;
import org.godotengine.godot.R;
// -- GODOT end --
import java.io.File;

View file

@ -18,7 +18,7 @@ package com.google.android.vending.expansion.downloader.impl;
// -- GODOT start --
//import com.android.vending.expansion.downloader.R;
import com.godot.game.R;
import org.godotengine.godot.R;
// -- GODOT end --
import com.google.android.vending.expansion.downloader.DownloadProgressInfo;

Some files were not shown because too many files have changed in this diff Show more