Android port of the Godot Editor
These set of changes focus primarily on getting the core logic and overall Godot Editor UI and functionality up and running natively on Android devices. UI tweaks / cleanup / polish, as well configuration for Android specific functionality / restrictions will be addressed in follow-up PRs iteratively based on feedback. Co-authored-by: thebestnom <shoval.arad@gmail.com>
This commit is contained in:
parent
0c7a15d777
commit
5711037bf6
|
@ -635,6 +635,9 @@ void EditorNode::_notification(int p_what) {
|
|||
get_tree()->get_root()->set_snap_2d_transforms_to_pixel(false);
|
||||
get_tree()->get_root()->set_snap_2d_vertices_to_pixel(false);
|
||||
get_tree()->set_auto_accept_quit(false);
|
||||
#ifdef ANDROID_ENABLED
|
||||
get_tree()->set_quit_on_go_back(false);
|
||||
#endif
|
||||
get_tree()->get_root()->connect("files_dropped", callable_mp(this, &EditorNode::_dropped_files));
|
||||
|
||||
command_palette->register_shortcuts_as_command();
|
||||
|
|
|
@ -2276,9 +2276,10 @@ bool Main::start() {
|
|||
|
||||
bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", true);
|
||||
|
||||
if (OS::get_singleton()->is_single_window() || (!project_manager && !editor && embed_subwindows)) {
|
||||
if (OS::get_singleton()->is_single_window() || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
|
||||
sml->get_root()->set_embedding_subwindows(true);
|
||||
}
|
||||
|
||||
ResourceLoader::add_custom_loaders();
|
||||
ResourceSaver::add_custom_savers();
|
||||
|
||||
|
|
|
@ -53,10 +53,17 @@ else:
|
|||
if lib_arch_dir != "":
|
||||
if env["target"] == "release":
|
||||
lib_type_dir = "release"
|
||||
else: # release_debug, debug
|
||||
elif env["target"] == "release_debug":
|
||||
lib_type_dir = "debug"
|
||||
else: # debug
|
||||
lib_type_dir = "dev"
|
||||
|
||||
out_dir = "#platform/android/java/lib/libs/" + lib_type_dir + "/" + lib_arch_dir
|
||||
if env["tools"]:
|
||||
lib_tools_dir = "tools/"
|
||||
else:
|
||||
lib_tools_dir = ""
|
||||
|
||||
out_dir = "#platform/android/java/lib/libs/" + lib_tools_dir + lib_type_dir + "/" + lib_arch_dir
|
||||
env_android.Command(
|
||||
out_dir + "/libgodot_android.so", "#bin/libgodot" + env["SHLIBSUFFIX"], Move("$TARGET", "$SOURCE")
|
||||
)
|
||||
|
|
|
@ -33,6 +33,11 @@ allprojects {
|
|||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
// Initializes a placeholder for the devImplementation dependency configuration.
|
||||
devImplementation {}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation libraries.kotlinStdLib
|
||||
implementation libraries.androidxFragment
|
||||
|
@ -45,6 +50,7 @@ dependencies {
|
|||
// 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'])
|
||||
devImplementation fileTree(dir: 'libs/dev', include: ['*.jar', '*.aar'])
|
||||
releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar'])
|
||||
}
|
||||
|
||||
|
@ -66,6 +72,7 @@ dependencies {
|
|||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
buildToolsVersion versions.buildTools
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.javaVersion
|
||||
|
@ -93,6 +100,8 @@ android {
|
|||
versionName getExportVersionName()
|
||||
minSdkVersion getExportMinSdkVersion()
|
||||
targetSdkVersion getExportTargetSdkVersion()
|
||||
|
||||
missingDimensionStrategy 'products', 'template'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
|
@ -146,6 +155,18 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
dev {
|
||||
initWith debug
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for custom builds.
|
||||
zipAlignEnabled shouldZipAlign()
|
||||
if (shouldSign()) {
|
||||
signingConfig signingConfigs.debug
|
||||
} else {
|
||||
signingConfig null
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for custom builds.
|
||||
|
@ -167,6 +188,7 @@ android {
|
|||
assets.srcDirs = ['assets']
|
||||
}
|
||||
debug.jniLibs.srcDirs = ['libs/debug', 'libs/debug/vulkan_validation_layers']
|
||||
dev.jniLibs.srcDirs = ['libs/dev']
|
||||
release.jniLibs.srcDirs = ['libs/release']
|
||||
}
|
||||
|
||||
|
@ -183,6 +205,12 @@ task copyAndRenameDebugApk(type: Copy) {
|
|||
rename "android_debug.apk", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameDevApk(type: Copy) {
|
||||
from "$buildDir/outputs/apk/dev/android_dev.apk"
|
||||
into getExportPath()
|
||||
rename "android_dev.apk", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameReleaseApk(type: Copy) {
|
||||
from "$buildDir/outputs/apk/release/android_release.apk"
|
||||
into getExportPath()
|
||||
|
@ -195,6 +223,12 @@ task copyAndRenameDebugAab(type: Copy) {
|
|||
rename "build-debug.aab", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameDevAab(type: Copy) {
|
||||
from "$buildDir/outputs/bundle/dev/build-dev.aab"
|
||||
into getExportPath()
|
||||
rename "build-dev.aab", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameReleaseAab(type: Copy) {
|
||||
from "$buildDir/outputs/bundle/release/build-release.aab"
|
||||
into getExportPath()
|
||||
|
|
|
@ -76,7 +76,7 @@ ext.getGodotEditorVersion = { ->
|
|||
String editorVersion = project.hasProperty("godot_editor_version") ? project.property("godot_editor_version") : ""
|
||||
if (editorVersion == null || editorVersion.isEmpty()) {
|
||||
// Try the library version first
|
||||
editorVersion = getGodotLibraryVersion()
|
||||
editorVersion = getGodotLibraryVersionName()
|
||||
|
||||
if (editorVersion.isEmpty()) {
|
||||
// Fallback value.
|
||||
|
@ -86,9 +86,24 @@ ext.getGodotEditorVersion = { ->
|
|||
return editorVersion
|
||||
}
|
||||
|
||||
ext.getGodotLibraryVersionCode = { ->
|
||||
String versionName = ""
|
||||
int versionCode = 1
|
||||
(versionName, versionCode) = getGodotLibraryVersion()
|
||||
return versionCode
|
||||
}
|
||||
|
||||
ext.getGodotLibraryVersionName = { ->
|
||||
String versionName = ""
|
||||
int versionCode = 1
|
||||
(versionName, versionCode) = getGodotLibraryVersion()
|
||||
return versionName
|
||||
}
|
||||
|
||||
ext.generateGodotLibraryVersion = { List<String> requiredKeys ->
|
||||
// Attempt to read the version from the `version.py` file.
|
||||
String libraryVersion = ""
|
||||
String libraryVersionName = ""
|
||||
int libraryVersionCode = 0
|
||||
|
||||
File versionFile = new File("../../../version.py")
|
||||
if (versionFile.isFile()) {
|
||||
|
@ -109,15 +124,35 @@ ext.generateGodotLibraryVersion = { List<String> requiredKeys ->
|
|||
}
|
||||
|
||||
if (requiredKeys.empty) {
|
||||
libraryVersion = map.values().join(".")
|
||||
libraryVersionName = map.values().join(".")
|
||||
try {
|
||||
if (map.containsKey("patch")) {
|
||||
libraryVersionCode = Integer.parseInt(map["patch"])
|
||||
}
|
||||
|
||||
if (map.containsKey("minor")) {
|
||||
libraryVersionCode += (Integer.parseInt(map["minor"]) * 100)
|
||||
}
|
||||
|
||||
if (map.containsKey("major")) {
|
||||
libraryVersionCode += (Integer.parseInt(map["major"]) * 10000)
|
||||
}
|
||||
} catch (NumberFormatException ignore) {
|
||||
libraryVersionCode = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (libraryVersion.isEmpty()) {
|
||||
if (libraryVersionName.isEmpty()) {
|
||||
// Fallback value in case we're unable to read the file.
|
||||
libraryVersion = "custom_build"
|
||||
libraryVersionName = "custom_build"
|
||||
}
|
||||
return libraryVersion
|
||||
|
||||
if (libraryVersionCode == 0) {
|
||||
libraryVersionCode = 1
|
||||
}
|
||||
|
||||
return [libraryVersionName, libraryVersionCode]
|
||||
}
|
||||
|
||||
ext.getGodotLibraryVersion = { ->
|
||||
|
@ -127,7 +162,10 @@ ext.getGodotLibraryVersion = { ->
|
|||
|
||||
ext.getGodotPublishVersion = { ->
|
||||
List<String> requiredKeys = ["major", "minor", "patch", "status"]
|
||||
return generateGodotLibraryVersion(requiredKeys)
|
||||
String versionName = ""
|
||||
int versionCode = 1
|
||||
(versionName, versionCode) = generateGodotLibraryVersion(requiredKeys)
|
||||
return versionName
|
||||
}
|
||||
|
||||
final String VALUE_SEPARATOR_REGEX = "\\|"
|
||||
|
|
|
@ -26,21 +26,22 @@ allprojects {
|
|||
|
||||
ext {
|
||||
supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
|
||||
supportedTargets = ["release", "debug"]
|
||||
supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"]
|
||||
supportedFlavors = ["editor", "template"]
|
||||
|
||||
// Used by gradle to specify which architecture to build for by default when running `./gradlew build`.
|
||||
// This command is usually used by Android Studio.
|
||||
// Used by gradle to specify which architecture to build for by default when running
|
||||
// `./gradlew build` (this command is usually used by Android Studio).
|
||||
// If building manually on the command line, it's recommended to use the
|
||||
// `./gradlew generateGodotTemplates` build command instead after running the `scons` command.
|
||||
// The defaultAbi must be one of the {supportedAbis} values.
|
||||
defaultAbi = "arm64v8"
|
||||
// `./gradlew generateGodotTemplates` build command instead after running the `scons` command(s).
|
||||
// The {selectedAbis} values must be from the {supportedAbis} values.
|
||||
selectedAbis = ["arm64v8"]
|
||||
}
|
||||
|
||||
def rootDir = "../../.."
|
||||
def binDir = "$rootDir/bin/"
|
||||
|
||||
def getSconsTaskName(String buildType) {
|
||||
return "compileGodotNativeLibs" + buildType.capitalize()
|
||||
def getSconsTaskName(String flavor, String buildType, String abi) {
|
||||
return "compileGodotNativeLibs" + flavor.capitalize() + buildType.capitalize() + abi.capitalize()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,6 +55,17 @@ task copyDebugBinaryToBin(type: Copy) {
|
|||
include('android_debug.apk')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the generated 'android_dev.apk' binary template into the Godot bin directory.
|
||||
* Depends on the app build task to ensure the binary is generated prior to copying.
|
||||
*/
|
||||
task copyDevBinaryToBin(type: Copy) {
|
||||
dependsOn ':app:assembleDev'
|
||||
from('app/build/outputs/apk/dev')
|
||||
into(binDir)
|
||||
include('android_dev.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.
|
||||
|
@ -70,7 +82,7 @@ task copyReleaseBinaryToBin(type: Copy) {
|
|||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDebugAARToAppModule(type: Copy) {
|
||||
dependsOn ':lib:assembleDebug'
|
||||
dependsOn ':lib:assembleTemplateDebug'
|
||||
from('lib/build/outputs/aar')
|
||||
into('app/libs/debug')
|
||||
include('godot-lib.debug.aar')
|
||||
|
@ -81,18 +93,40 @@ task copyDebugAARToAppModule(type: Copy) {
|
|||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDebugAARToBin(type: Copy) {
|
||||
dependsOn ':lib:assembleDebug'
|
||||
dependsOn ':lib:assembleTemplateDebug'
|
||||
from('lib/build/outputs/aar')
|
||||
into(binDir)
|
||||
include('godot-lib.debug.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive dev file into the app module dev libs directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDevAARToAppModule(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateDev'
|
||||
from('lib/build/outputs/aar')
|
||||
into('app/libs/dev')
|
||||
include('godot-lib.dev.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive dev file into the root bin directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDevAARToBin(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateDev'
|
||||
from('lib/build/outputs/aar')
|
||||
into(binDir)
|
||||
include('godot-lib.dev.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive release file into the app module release libs directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyReleaseAARToAppModule(type: Copy) {
|
||||
dependsOn ':lib:assembleRelease'
|
||||
dependsOn ':lib:assembleTemplateRelease'
|
||||
from('lib/build/outputs/aar')
|
||||
into('app/libs/release')
|
||||
include('godot-lib.release.aar')
|
||||
|
@ -103,7 +137,7 @@ task copyReleaseAARToAppModule(type: Copy) {
|
|||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyReleaseAARToBin(type: Copy) {
|
||||
dependsOn ':lib:assembleRelease'
|
||||
dependsOn ':lib:assembleTemplateRelease'
|
||||
from('lib/build/outputs/aar')
|
||||
into(binDir)
|
||||
include('godot-lib.release.aar')
|
||||
|
@ -111,7 +145,7 @@ task copyReleaseAARToBin(type: Copy) {
|
|||
|
||||
/**
|
||||
* 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'.
|
||||
* as the AAR files generated by 'copyDebugAAR', 'copyDevAAR' and 'copyReleaseAAR'.
|
||||
* The zip file also includes some gradle tools to allow building of the custom build.
|
||||
*/
|
||||
task zipCustomBuild(type: Zip) {
|
||||
|
@ -130,8 +164,18 @@ def templateExcludedBuildTask() {
|
|||
def excludedTasks = []
|
||||
if (!isAndroidStudio()) {
|
||||
logger.lifecycle("Excluding Android studio build tasks")
|
||||
for (String buildType : supportedTargets) {
|
||||
excludedTasks += ":lib:" + getSconsTaskName(buildType)
|
||||
for (String flavor : supportedFlavors) {
|
||||
for (String buildType : supportedTargetsMap.keySet()) {
|
||||
if (buildType == "release" && flavor == "editor") {
|
||||
// The editor can't be used with target=release as debugging tools are then not
|
||||
// included, and it would crash on errors instead of reporting them.
|
||||
continue
|
||||
}
|
||||
|
||||
for (String abi : selectedAbis) {
|
||||
excludedTasks += ":lib:" + getSconsTaskName(flavor, buildType, abi)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return excludedTasks
|
||||
|
@ -141,7 +185,7 @@ def templateBuildTasks() {
|
|||
def tasks = []
|
||||
|
||||
// Only build the apks and aar files for which we have native shared libraries.
|
||||
for (String target : supportedTargets) {
|
||||
for (String target : supportedTargetsMap.keySet()) {
|
||||
File targetLibs = new File("lib/libs/" + target)
|
||||
if (targetLibs != null
|
||||
&& targetLibs.isDirectory()
|
||||
|
@ -167,6 +211,50 @@ def isAndroidStudio() {
|
|||
return sysProps != null && sysProps['idea.platform.prefix'] != null
|
||||
}
|
||||
|
||||
task copyEditorDebugBinaryToBin(type: Copy) {
|
||||
dependsOn ':editor:assembleDebug'
|
||||
from('editor/build/outputs/apk/debug')
|
||||
into(binDir)
|
||||
include('android_editor.apk')
|
||||
}
|
||||
|
||||
task copyEditorDevBinaryToBin(type: Copy) {
|
||||
dependsOn ':editor:assembleDev'
|
||||
from('editor/build/outputs/apk/dev')
|
||||
into(binDir)
|
||||
include('android_editor_dev.apk')
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the Godot Editor Android apk.
|
||||
*
|
||||
* Note: The Godot 'tools' shared libraries must have been generated (via scons) prior to running
|
||||
* this gradle task. The task will only build the apk(s) for which the shared libraries is
|
||||
* available.
|
||||
*/
|
||||
task generateGodotEditor {
|
||||
gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
|
||||
|
||||
def tasks = []
|
||||
|
||||
for (String target : supportedTargetsMap.keySet()) {
|
||||
if (target == "release") {
|
||||
// The editor can't be used with target=release as debugging tools are then not
|
||||
// included, and it would crash on errors instead of reporting them.
|
||||
continue
|
||||
}
|
||||
File targetLibs = new File("lib/libs/tools/" + target)
|
||||
if (targetLibs != null
|
||||
&& targetLibs.isDirectory()
|
||||
&& targetLibs.listFiles() != null
|
||||
&& targetLibs.listFiles().length > 0) {
|
||||
tasks += "copyEditor${target.capitalize()}BinaryToBin"
|
||||
}
|
||||
}
|
||||
|
||||
dependsOn = tasks
|
||||
}
|
||||
|
||||
/**
|
||||
* Master task used to coordinate the tasks defined above to generate the set of Godot templates.
|
||||
*/
|
||||
|
@ -191,7 +279,27 @@ task generateDevTemplate {
|
|||
}
|
||||
|
||||
/**
|
||||
* Clean the generated artifacts.
|
||||
* Clean the generated editor artifacts.
|
||||
*/
|
||||
task cleanGodotEditor(type: Delete) {
|
||||
// Delete the generated native tools libs
|
||||
delete("lib/libs/tools")
|
||||
|
||||
// Delete the library generated AAR files
|
||||
delete("lib/build/outputs/aar")
|
||||
|
||||
// Delete the generated binary apks
|
||||
delete("editor/build/outputs/apk")
|
||||
|
||||
// Delete the Godot editor apks in the Godot bin directory
|
||||
delete("$binDir/android_editor.apk")
|
||||
delete("$binDir/android_editor_dev.apk")
|
||||
|
||||
finalizedBy getTasksByName("clean", true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the generated template artifacts.
|
||||
*/
|
||||
task cleanGodotTemplates(type: Delete) {
|
||||
// Delete the generated native libs
|
||||
|
@ -208,9 +316,11 @@ task cleanGodotTemplates(type: Delete) {
|
|||
|
||||
// Delete the Godot templates in the Godot bin directory
|
||||
delete("$binDir/android_debug.apk")
|
||||
delete("$binDir/android_dev.apk")
|
||||
delete("$binDir/android_release.apk")
|
||||
delete("$binDir/android_source.zip")
|
||||
delete("$binDir/godot-lib.debug.aar")
|
||||
delete("$binDir/godot-lib.dev.aar")
|
||||
delete("$binDir/godot-lib.release.aar")
|
||||
|
||||
finalizedBy getTasksByName("clean", true)
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// Gradle build config for Godot Engine's Android port.
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
dependencies {
|
||||
implementation libraries.kotlinStdLib
|
||||
implementation libraries.androidxFragment
|
||||
implementation project(":lib")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
buildToolsVersion versions.buildTools
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
defaultConfig {
|
||||
// The 'applicationId' suffix allows to install Godot 3.x(v3) and 4.x(v4) on the same device
|
||||
applicationId "org.godotengine.editor.v4"
|
||||
versionCode getGodotLibraryVersionCode()
|
||||
versionName getGodotLibraryVersionName()
|
||||
minSdkVersion versions.minSdk
|
||||
//noinspection ExpiredTargetSdkVersion - Restrict to version 29 until https://github.com/godotengine/godot/pull/51815 is submitted
|
||||
targetSdkVersion 29 // versions.targetSdk
|
||||
|
||||
missingDimensionStrategy 'products', 'editor'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.javaVersion
|
||||
targetCompatibility versions.javaVersion
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
dev {
|
||||
initWith debug
|
||||
applicationIdSuffix ".dev"
|
||||
}
|
||||
|
||||
debug {
|
||||
initWith release
|
||||
|
||||
// Need to swap with the release signing config when this is ready for public release.
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
||||
release {
|
||||
// This buildtype is disabled below.
|
||||
// The editor can't be used with target=release only, as debugging tools are then not
|
||||
// included, and it would crash on errors instead of reporting them.
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
// 'doNotStrip' is enabled for development within Android Studio
|
||||
if (shouldNotStrip()) {
|
||||
doNotStrip '**/*.so'
|
||||
}
|
||||
}
|
||||
|
||||
// Disable 'release' buildtype.
|
||||
// The editor can't be used with target=release only, as debugging tools are then not
|
||||
// included, and it would crash on errors instead of reporting them.
|
||||
variantFilter { variant ->
|
||||
if (variant.buildType.name == "release") {
|
||||
setIgnore(true)
|
||||
}
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all { output ->
|
||||
def suffix = variant.name == "dev" ? "_dev" : ""
|
||||
output.outputFileName = "android_editor${suffix}.apk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="godot_editor_name_string">Godot Editor 4.x (dev)</string>
|
||||
</resources>
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.godotengine.editor"
|
||||
android:installLocation="auto">
|
||||
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="true"
|
||||
android:xlargeScreens="true" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/icon"
|
||||
android:label="@string/godot_editor_name_string"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
|
||||
<activity
|
||||
android:name=".GodotProjectManager"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="false"
|
||||
android:screenOrientation="landscape"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
|
||||
android:process=":GodotProjectManager">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".GodotEditor"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:process=":GodotEditor"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="false"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".GodotGame"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:process=":GodotGame"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="false"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,110 @@
|
|||
/*************************************************************************/
|
||||
/* GodotEditor.java */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
package org.godotengine.editor;
|
||||
|
||||
import org.godotengine.godot.FullScreenGodotApp;
|
||||
import org.godotengine.godot.utils.PermissionsUtil;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for the Godot Android Editor activities.
|
||||
*
|
||||
* This provides the basic templates for the activities making up this application.
|
||||
* Each derived activity runs in its own process, which enable up to have several instances of
|
||||
* the Godot engine up and running at the same time.
|
||||
*
|
||||
* It also plays the role of the primary editor window.
|
||||
*/
|
||||
public class GodotEditor extends FullScreenGodotApp {
|
||||
private static final boolean WAIT_FOR_DEBUGGER = false;
|
||||
private static final String COMMAND_LINE_PARAMS = "command_line_params";
|
||||
|
||||
private static final String EDITOR_ARG = "--editor";
|
||||
private static final String PROJECT_MANAGER_ARG = "--project-manager";
|
||||
|
||||
private final List<String> commandLineParams = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
PermissionsUtil.requestManifestPermissions(this);
|
||||
|
||||
String[] params = getIntent().getStringArrayExtra(COMMAND_LINE_PARAMS);
|
||||
updateCommandLineParams(params);
|
||||
|
||||
if (BuildConfig.BUILD_TYPE.equals("debug") && WAIT_FOR_DEBUGGER) {
|
||||
Debug.waitForDebugger();
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
private void updateCommandLineParams(@Nullable String[] args) {
|
||||
// Update the list of command line params with the new args
|
||||
commandLineParams.clear();
|
||||
if (args != null && args.length > 0) {
|
||||
commandLineParams.addAll(Arrays.asList(args));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCommandLine() {
|
||||
return commandLineParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewGodotInstanceRequested(String[] args) {
|
||||
// Parse the arguments to figure out which activity to start.
|
||||
Class<?> targetClass = GodotGame.class;
|
||||
for (String arg : args) {
|
||||
if (EDITOR_ARG.equals(arg)) {
|
||||
targetClass = GodotEditor.class;
|
||||
break;
|
||||
}
|
||||
|
||||
if (PROJECT_MANAGER_ARG.equals(arg)) {
|
||||
targetClass = GodotProjectManager.class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Launch a new activity
|
||||
Intent newInstance = new Intent(this, targetClass).putExtra(COMMAND_LINE_PARAMS, args);
|
||||
startActivity(newInstance);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*************************************************************************/
|
||||
/* GodotGame.java */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
package org.godotengine.editor;
|
||||
|
||||
/**
|
||||
* Drives the 'run project' window of the Godot Editor.
|
||||
*/
|
||||
public class GodotGame extends GodotEditor {
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*************************************************************************/
|
||||
/* GodotProjectManager.java */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
package org.godotengine.editor;
|
||||
|
||||
/**
|
||||
* Launcher activity for the Godot Android Editor.
|
||||
*
|
||||
* It presents the user with the project manager interface.
|
||||
* Upon selection of a project, this activity (via its parent logic) starts the
|
||||
* {@link GodotEditor} activity.
|
||||
*/
|
||||
public class GodotProjectManager extends GodotEditor {
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="godot_editor_name_string">Godot Editor 4.x</string>
|
||||
</resources>
|
|
@ -18,14 +18,13 @@ def pathToRootDir = "../../../../"
|
|||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
buildToolsVersion versions.buildTools
|
||||
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion versions.minSdk
|
||||
targetSdkVersion versions.targetSdk
|
||||
|
||||
manifestPlaceholders = [godotLibraryVersion: getGodotLibraryVersion()]
|
||||
manifestPlaceholders = [godotLibraryVersion: getGodotLibraryVersionName()]
|
||||
}
|
||||
|
||||
namespace = "org.godotengine.godot"
|
||||
|
@ -35,6 +34,18 @@ android {
|
|||
targetCompatibility versions.javaVersion
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
dev {
|
||||
initWith debug
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "products"
|
||||
productFlavors {
|
||||
editor {}
|
||||
template {}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
disable 'MissingTranslation', 'UnusedResources'
|
||||
|
@ -58,24 +69,50 @@ android {
|
|||
aidl.srcDirs = ['aidl']
|
||||
assets.srcDirs = ['assets']
|
||||
}
|
||||
|
||||
debug.jniLibs.srcDirs = ['libs/debug']
|
||||
dev.jniLibs.srcDirs = ['libs/dev']
|
||||
release.jniLibs.srcDirs = ['libs/release']
|
||||
|
||||
// Editor jni library
|
||||
editorDebug.jniLibs.srcDirs = ['libs/tools/debug']
|
||||
editorDev.jniLibs.srcDirs = ['libs/tools/dev']
|
||||
}
|
||||
|
||||
// Disable 'editorRelease'.
|
||||
// The editor can't be used with target=release as debugging tools are then not
|
||||
// included, and it would crash on errors instead of reporting them.
|
||||
variantFilter { variant ->
|
||||
if (variant.name == "editorRelease") {
|
||||
setIgnore(true)
|
||||
}
|
||||
}
|
||||
|
||||
libraryVariants.all { variant ->
|
||||
def flavorName = variant.getFlavorName()
|
||||
if (flavorName == null || flavorName == "") {
|
||||
throw new GradleException("Invalid product flavor: $flavorName")
|
||||
}
|
||||
|
||||
boolean toolsFlag = flavorName == "editor"
|
||||
|
||||
def buildType = variant.buildType.name
|
||||
if (buildType == null || buildType == "" || !supportedTargetsMap.containsKey(buildType)) {
|
||||
throw new GradleException("Invalid build type: $buildType")
|
||||
}
|
||||
|
||||
def sconsTarget = supportedTargetsMap[buildType]
|
||||
if (sconsTarget == null || sconsTarget == "") {
|
||||
throw new GradleException("Invalid scons target: $sconsTarget")
|
||||
}
|
||||
|
||||
// Update the name of the generated library
|
||||
def outputSuffix = "${buildType}.aar"
|
||||
if (toolsFlag) {
|
||||
outputSuffix = "tools.$outputSuffix"
|
||||
}
|
||||
variant.outputs.all { output ->
|
||||
output.outputFileName = "godot-lib.${variant.name}.aar"
|
||||
}
|
||||
|
||||
def buildType = variant.buildType.name.capitalize()
|
||||
|
||||
def releaseTarget = buildType.toLowerCase()
|
||||
if (releaseTarget == null || releaseTarget == "") {
|
||||
throw new GradleException("Invalid build type: " + buildType)
|
||||
}
|
||||
|
||||
if (!supportedAbis.contains(defaultAbi)) {
|
||||
throw new GradleException("Invalid default abi: " + defaultAbi)
|
||||
output.outputFileName = "godot-lib.${outputSuffix}"
|
||||
}
|
||||
|
||||
// Find scons' executable path
|
||||
|
@ -88,13 +125,11 @@ android {
|
|||
for (ext in sconsExts) {
|
||||
String sconsNameExt = sconsName + ext
|
||||
logger.lifecycle("Checking $sconsNameExt")
|
||||
|
||||
sconsExecutableFile = org.gradle.internal.os.OperatingSystem.current().findInPath(sconsNameExt)
|
||||
if (sconsExecutableFile != null) {
|
||||
// We're done!
|
||||
break
|
||||
}
|
||||
|
||||
// Check all the options in path
|
||||
List<File> allOptions = org.gradle.internal.os.OperatingSystem.current().findAllInPath(sconsNameExt)
|
||||
if (!allOptions.isEmpty()) {
|
||||
|
@ -103,27 +138,32 @@ android {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (sconsExecutableFile == null) {
|
||||
throw new GradleException("Unable to find executable path for the '$sconsName' command.")
|
||||
} else {
|
||||
logger.lifecycle("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}")
|
||||
}
|
||||
|
||||
// Creating gradle task to generate the native libraries for the default abi.
|
||||
def taskName = getSconsTaskName(buildType)
|
||||
tasks.create(name: taskName, type: Exec) {
|
||||
executable sconsExecutableFile.absolutePath
|
||||
args "--directory=${pathToRootDir}", "platform=android", "target=${releaseTarget}", "android_arch=${defaultAbi}", "-j" + Runtime.runtime.availableProcessors()
|
||||
}
|
||||
for (String selectedAbi : selectedAbis) {
|
||||
if (!supportedAbis.contains(selectedAbi)) {
|
||||
throw new GradleException("Invalid selected abi: $selectedAbi")
|
||||
}
|
||||
|
||||
// Schedule the tasks so the generated libs are present before the aar file is packaged.
|
||||
tasks["merge${buildType}JniLibFolders"].dependsOn taskName
|
||||
// Creating gradle task to generate the native libraries for the selected abi.
|
||||
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
|
||||
tasks.create(name: taskName, type: Exec) {
|
||||
executable sconsExecutableFile.absolutePath
|
||||
args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "android_arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
|
||||
}
|
||||
|
||||
// Schedule the tasks so the generated libs are present before the aar file is packaged.
|
||||
tasks["merge${flavorName.capitalize()}${buildType.capitalize()}JniLibFolders"].dependsOn taskName
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Enable when issues with AGP 7.1+ are resolved (https://github.com/GodotVR/godot_openxr/issues/187).
|
||||
// publishing {
|
||||
// singleVariant("release") {
|
||||
// singleVariant("templateRelease") {
|
||||
// withSourcesJar()
|
||||
// withJavadocJar()
|
||||
// }
|
||||
|
|
|
@ -47,7 +47,6 @@ import android.app.AlertDialog;
|
|||
import android.app.PendingIntent;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -333,9 +332,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
|||
}
|
||||
|
||||
public void restart() {
|
||||
if (godotHost != null) {
|
||||
godotHost.onGodotRestartRequested(this);
|
||||
}
|
||||
runOnUiThread(() -> {
|
||||
if (godotHost != null) {
|
||||
godotHost.onGodotRestartRequested(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void alert(final String message, final String title) {
|
||||
|
@ -859,9 +860,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
|||
private void forceQuit() {
|
||||
// TODO: This is a temp solution. The proper fix will involve tracking down and properly shutting down each
|
||||
// native Godot components that is started in Godot#onVideoInit.
|
||||
if (godotHost != null) {
|
||||
godotHost.onGodotForceQuit(this);
|
||||
}
|
||||
runOnUiThread(() -> {
|
||||
if (godotHost != null) {
|
||||
godotHost.onGodotForceQuit(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean obbIsCorrupted(String f, String main_pack_md5) {
|
||||
|
@ -1010,6 +1013,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
|||
mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress,
|
||||
progress.mOverallTotal));
|
||||
}
|
||||
|
||||
public void initInputDevices() {
|
||||
mRenderView.initInputDevices();
|
||||
}
|
||||
|
@ -1018,4 +1022,13 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
|||
private GodotRenderView getRenderView() { // used by native side to get renderView
|
||||
return mRenderView;
|
||||
}
|
||||
|
||||
@Keep
|
||||
private void createNewGodotInstance(String[] args) {
|
||||
runOnUiThread(() -> {
|
||||
if (godotHost != null) {
|
||||
godotHost.onNewGodotInstanceRequested(args);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,16 @@ public interface GodotHost {
|
|||
default void onGodotForceQuit(Godot instance) {}
|
||||
|
||||
/**
|
||||
* Invoked on the GL thread when the Godot instance wants to be restarted. It's up to the host
|
||||
* Invoked on the UI thread when the Godot instance wants to be restarted. It's up to the host
|
||||
* to perform the appropriate action(s).
|
||||
*/
|
||||
default void onGodotRestartRequested(Godot instance) {}
|
||||
|
||||
/**
|
||||
* Invoked on the UI thread when a new Godot instance is requested. It's up to the host to
|
||||
* perform the appropriate action(s).
|
||||
*
|
||||
* @param args Arguments used to initialize the new instance.
|
||||
*/
|
||||
default void onNewGodotInstanceRequested(String[] args) {}
|
||||
}
|
||||
|
|
|
@ -16,3 +16,5 @@ add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
|
|||
target_include_directories(${PROJECT_NAME}
|
||||
SYSTEM PUBLIC
|
||||
${GODOT_ROOT_DIR})
|
||||
|
||||
add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DTOOLS_ENABLED)
|
||||
|
|
|
@ -6,6 +6,7 @@ plugins {
|
|||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
buildToolsVersion versions.buildTools
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion versions.minSdk
|
||||
|
@ -28,8 +29,6 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
|
|
|
@ -7,20 +7,15 @@ version = PUBLISH_VERSION
|
|||
afterEvaluate {
|
||||
publishing {
|
||||
publications {
|
||||
release(MavenPublication) {
|
||||
templateRelease(MavenPublication) {
|
||||
from components.templateRelease
|
||||
|
||||
// The coordinates of the library, being set from variables that
|
||||
// we'll set up later
|
||||
groupId ossrhGroupId
|
||||
artifactId PUBLISH_ARTIFACT_ID
|
||||
version PUBLISH_VERSION
|
||||
|
||||
// Two artifacts, the `aar` (or `jar`) and the sources
|
||||
if (project.plugins.findPlugin("com.android.library")) {
|
||||
from components.release
|
||||
} else {
|
||||
from components.java
|
||||
}
|
||||
|
||||
// Mostly self-explanatory metadata
|
||||
pom {
|
||||
name = PUBLISH_ARTIFACT_ID
|
||||
|
|
|
@ -4,6 +4,7 @@ rootProject.name = "Godot"
|
|||
include ':app'
|
||||
include ':lib'
|
||||
include ':nativeSrcsConfigs'
|
||||
include ':editor'
|
||||
|
||||
include ':assetPacks:installTime'
|
||||
project(':assetPacks:installTime').projectDir = file("app/assetPacks/installTime")
|
||||
|
|
|
@ -107,6 +107,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
|
|||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz) {
|
||||
// lets cleanup
|
||||
if (java_class_wrapper) {
|
||||
memdelete(java_class_wrapper);
|
||||
}
|
||||
if (godot_io_java) {
|
||||
delete godot_io_java;
|
||||
}
|
||||
|
@ -117,6 +120,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
|
|||
delete input_handler;
|
||||
}
|
||||
if (os_android) {
|
||||
os_android->main_loop_end();
|
||||
delete os_android;
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +150,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
|
|||
}
|
||||
}
|
||||
|
||||
Error err = Main::setup("apk", cmdlen, (char **)cmdline, false);
|
||||
Error err = Main::setup(OS_Android::ANDROID_EXEC_PATH, cmdlen, (char **)cmdline, false);
|
||||
if (cmdline) {
|
||||
if (j_cmdline) {
|
||||
for (int i = 0; i < cmdlen; ++i) {
|
||||
|
|
|
@ -77,6 +77,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
|
|||
_get_input_fallback_mapping = p_env->GetMethodID(godot_class, "getInputFallbackMapping", "()Ljava/lang/String;");
|
||||
_on_godot_setup_completed = p_env->GetMethodID(godot_class, "onGodotSetupCompleted", "()V");
|
||||
_on_godot_main_loop_started = p_env->GetMethodID(godot_class, "onGodotMainLoopStarted", "()V");
|
||||
_create_new_godot_instance = p_env->GetMethodID(godot_class, "createNewGodotInstance", "([Ljava/lang/String;)V");
|
||||
|
||||
// get some Activity method pointers...
|
||||
_get_class_loader = p_env->GetMethodID(activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
|
@ -351,3 +352,16 @@ void GodotJavaWrapper::vibrate(int p_duration_ms) {
|
|||
env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void GodotJavaWrapper::create_new_godot_instance(List<String> args) {
|
||||
if (_create_new_godot_instance) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_COND(env == nullptr);
|
||||
|
||||
jobjectArray jargs = env->NewObjectArray(args.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
env->SetObjectArrayElement(jargs, i, env->NewStringUTF(args[i].utf8().get_data()));
|
||||
}
|
||||
env->CallVoidMethod(godot_instance, _create_new_godot_instance, jargs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include "core/templates/list.h"
|
||||
#include "java_godot_view_wrapper.h"
|
||||
#include "string_android.h"
|
||||
|
||||
|
@ -70,6 +71,7 @@ private:
|
|||
jmethodID _on_godot_setup_completed = 0;
|
||||
jmethodID _on_godot_main_loop_started = 0;
|
||||
jmethodID _get_class_loader = 0;
|
||||
jmethodID _create_new_godot_instance = 0;
|
||||
|
||||
public:
|
||||
GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_godot_instance);
|
||||
|
@ -103,6 +105,7 @@ public:
|
|||
bool is_activity_resumed();
|
||||
void vibrate(int p_duration_ms);
|
||||
String get_input_fallback_mapping();
|
||||
void create_new_godot_instance(List<String> args);
|
||||
};
|
||||
|
||||
#endif /* !JAVA_GODOT_WRAPPER_H */
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "drivers/unix/file_access_unix.h"
|
||||
#include "main/main.h"
|
||||
#include "platform/android/display_server_android.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
|
||||
#include "dir_access_jandroid.h"
|
||||
#include "file_access_android.h"
|
||||
|
@ -45,6 +46,8 @@
|
|||
#include "java_godot_io_wrapper.h"
|
||||
#include "java_godot_wrapper.h"
|
||||
|
||||
const char *OS_Android::ANDROID_EXEC_PATH = "apk";
|
||||
|
||||
String _remove_symlink(const String &dir) {
|
||||
// Workaround for Android 6.0+ using a symlink.
|
||||
// Save the current directory.
|
||||
|
@ -81,18 +84,28 @@ void OS_Android::alert(const String &p_alert, const String &p_title) {
|
|||
void OS_Android::initialize_core() {
|
||||
OS_Unix::initialize_core();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
|
||||
#else
|
||||
if (use_apk_expansion) {
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
|
||||
} else {
|
||||
FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
|
||||
}
|
||||
#endif
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES);
|
||||
#else
|
||||
if (use_apk_expansion) {
|
||||
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES);
|
||||
} else {
|
||||
DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_RESOURCES);
|
||||
}
|
||||
#endif
|
||||
|
||||
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
|
||||
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
|
@ -178,6 +191,10 @@ bool OS_Android::main_loop_iterate() {
|
|||
|
||||
void OS_Android::main_loop_end() {
|
||||
if (main_loop) {
|
||||
SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
|
||||
if (scene_tree) {
|
||||
scene_tree->quit();
|
||||
}
|
||||
main_loop->finalize();
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +214,11 @@ Error OS_Android::shell_open(String p_uri) {
|
|||
}
|
||||
|
||||
String OS_Android::get_resource_dir() const {
|
||||
#ifdef TOOLS_ENABLED
|
||||
return OS_Unix::get_resource_dir();
|
||||
#else
|
||||
return "/"; //android has its own filesystem for resources inside the APK
|
||||
#endif
|
||||
}
|
||||
|
||||
String OS_Android::get_locale() const {
|
||||
|
@ -222,6 +243,14 @@ String OS_Android::get_data_path() const {
|
|||
return get_user_data_dir();
|
||||
}
|
||||
|
||||
String OS_Android::get_executable_path() const {
|
||||
// Since unix process creation is restricted on Android, we bypass
|
||||
// OS_Unix::get_executable_path() so we can return ANDROID_EXEC_PATH.
|
||||
// Detection of ANDROID_EXEC_PATH allows to handle process creation in an Android compliant
|
||||
// manner.
|
||||
return OS::get_executable_path();
|
||||
}
|
||||
|
||||
String OS_Android::get_user_data_dir() const {
|
||||
if (!data_dir_cache.is_empty()) {
|
||||
return data_dir_cache;
|
||||
|
@ -294,6 +323,10 @@ void OS_Android::vibrate_handheld(int p_duration_ms) {
|
|||
godot_java->vibrate(p_duration_ms);
|
||||
}
|
||||
|
||||
String OS_Android::get_config_path() const {
|
||||
return get_user_data_dir().plus_file("config");
|
||||
}
|
||||
|
||||
bool OS_Android::_check_internal_feature_support(const String &p_feature) {
|
||||
if (p_feature == "mobile") {
|
||||
return true;
|
||||
|
@ -343,5 +376,26 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god
|
|||
DisplayServerAndroid::register_android_driver();
|
||||
}
|
||||
|
||||
Error OS_Android::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
if (p_path == ANDROID_EXEC_PATH) {
|
||||
return create_instance(p_arguments);
|
||||
} else {
|
||||
return OS_Unix::execute(p_path, p_arguments, r_pipe, r_exitcode, read_stderr, p_pipe_mutex, p_open_console);
|
||||
}
|
||||
}
|
||||
|
||||
Error OS_Android::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
|
||||
if (p_path == ANDROID_EXEC_PATH) {
|
||||
return create_instance(p_arguments, r_child_id);
|
||||
} else {
|
||||
return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console);
|
||||
}
|
||||
}
|
||||
|
||||
Error OS_Android::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) {
|
||||
godot_java->create_new_godot_instance(p_arguments);
|
||||
return OK;
|
||||
}
|
||||
|
||||
OS_Android::~OS_Android() {
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ private:
|
|||
GodotIOJavaWrapper *godot_io_java;
|
||||
|
||||
public:
|
||||
static const char *ANDROID_EXEC_PATH;
|
||||
|
||||
virtual void initialize_core() override;
|
||||
virtual void initialize() override;
|
||||
|
||||
|
@ -108,6 +110,7 @@ public:
|
|||
ANativeWindow *get_native_window() const;
|
||||
|
||||
virtual Error shell_open(String p_uri) override;
|
||||
virtual String get_executable_path() const override;
|
||||
virtual String get_user_data_dir() const override;
|
||||
virtual String get_data_path() const override;
|
||||
virtual String get_cache_path() const override;
|
||||
|
@ -121,6 +124,12 @@ public:
|
|||
|
||||
void vibrate_handheld(int p_duration_ms) override;
|
||||
|
||||
virtual String get_config_path() const override;
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
|
||||
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
|
||||
virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
|
||||
|
||||
virtual bool _check_internal_feature_support(const String &p_feature) override;
|
||||
OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion);
|
||||
~OS_Android();
|
||||
|
|
Loading…
Reference in New Issue