创建Android插件

介绍

在手机游戏货币化出现之前,让视频游戏便携化是一件好事。

这一领域很复杂,通常是一款可以盈利的移动游戏,需要与服务器进行特殊连接,例如:

  • 分析

  • 应用内购买

  • 收据验证

  • 安装跟踪

  • 广告

  • 视频广告

  • 交叉推广

  • 游戏中的软货币和硬货币

  • 促销代码

  • A/B测试

  • 登录

  • 云保存

  • 排行榜和分数

  • 用户支持和反馈

  • 发布到Facebook、Twitter等。

  • 提醒推送

在iOS上,你可以编写一个C++模块,利用C++与Objc的交互。即使使用gdantive也可以使其成为插件。

在Android上,通过JNI(Java原生接口)与C++接口不是很灵活,因此编写插件是相当多的工作。

也有可能你只想修改Android导出模板,通过使用插件,你的项目可以保持与较新的godot版本兼容(因为Android源模板将在每个版本上更新)。

也许休息一下

大多数这些API允许通过REST/JSON API进行通信。如果API相对简单并且不需要复杂的授权,那么这可能比编写特定的Android插件更好。

Godot非常支持HTTP、HTTPS和JSON,因此以这种方式实现的API也可以在每个平台上工作。

当然,在大多数情况下,只写一个Android插件更容易,所以继续阅读。

Android插件

编写一个Android插件现在可以开始godot 3.2了。这也很容易!不再需要重新编译引擎。

在进行任何操作之前,请确保您了解如何设置 custom build environment 对于Android。

您的插件需要位于除 "build/" 里面 "res://android" 目录(通过以上链接创建)。任何名称都可以,所以根据要实现的SDK(或者只是插件名称)来命名它。

一旦创建,就有一些规则要遵循,但它们很简单。

Android目录

在插件文件夹中,您可以使用标准文件夹,就像它们来自Android Gradle项目一样。例如:

src/ - For Java source code, same as in your Android project
res/ - For resources
aidl/ - For interfaces
assets/ - For assets that will be included as-is on export
libs/debug - For debug JNI libraries
libs/release - For release JNI libraries

Gradle将在构建时自动将它们视为项目的一部分,与默认项目文件相同。

“区块”文件

现在可以修改 "AndroidManifest.xml"build.gradle 在里面 "res://android/build" 直接和Godot将保持您的变化时,建设。但问题是,如果更新godot,还需要更新 build/ 文件夹和更改将丢失。

为了克服这个问题,godot android插件系统允许您创建 文件,您可以在其中指定可以同时插入 "AndroidManifest.xml"build.gradle . 每次Godot构建用于导出或部署的项目时都会插入它们。

AndroidManifest.conf

此文件允许将块的位插入 AndroidManifest.xml ,以下是支持的标记,完全可选:

[user_permissions]

此标记下面的任何文本位都插入到文件的<manifest>标记中。这通常用于权限标记。

[application]

文件的<application>标记内此标记下面的任何文本位。许多SDK都需要这样做。

[application_attribs]

这些是可以添加到<application>标记末尾的属性。有些SDK需要这样做。

gradle.conf

此文件允许将块的位插入 build.gradle ,以下是支持的,完全是可选的:

[buildscript_repositories]

此标记下面的任何文本位都插入到生成文件的buildscript.repositories部分中。

[buildscript_dependencies]

此标记下面的任何文本位都插入到生成文件的buildscript.dependencies部分中。

[allprojects_repositories]

此标记下面的任何文本位都插入到构建文件的allprojects.repositories部分中。

[dependencies]

此标记下面的任何文本位都插入到生成文件的依赖项部分中。

[android_defaultconfig]

此标记下面的任何文本位都插入构建文件的android.defaultconfig部分。

[global]

此标记下面的任何文本位都插入到生成文件的全局范围内。

爪哇独生子女

Android插件通常会有一个单独的类来加载它,这个类继承自 Godot.SingletonBase . 为模块提供的任何其他资源的资源标识符将位于 com.godot.game.R 类,因此您可能希望导入它。

单个对象模板如下:

package org.godotengine.godot;

import android.app.Activity;
import android.content.Intent;
import com.godot.game.R;
import javax.microedition.khronos.opengles.GL10;

public class MySingleton extends Godot.SingletonBase {

    protected Activity appActivity;
    protected Context appContext;
    private int instanceId = 0;

    public int myFunction(String p_str) {
        // A function to bind.
        return 1;
    }

    public void getInstanceId(int pInstanceId) {
        // You will need to call this method from Godot and pass in the get_instance_id().
        instanceId = pInstanceId;
    }

    static public Godot.SingletonBase initialize(Activity p_activity) {
        return new MySingleton(p_activity);
    }

    public MySingleton(Activity p_activity) {
        // Register class name and functions to bind.
        registerClass("MySingleton", new String[]
            {
                "myFunction",
                "getInstanceId"
            });
        this.appActivity = p_activity;
        this.appContext = appActivity.getApplicationContext();
        // You might want to try initializing your singleton here, but android
        // threads are weird and this runs in another thread, so to interact with Godot you usually have to do.
        activity.runOnUiThread(new Runnable() {
                public void run() {
                    // Useful way to get config info from "project.godot".
                    String key = GodotLib.getGlobal("plugin/api_key");
                    // SDK.initializeHere();
                }
        });

    }

    // Forwarded callbacks you can reimplement, as SDKs often need them.

    protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {}
    protected void onMainRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {}

    protected void onMainPause() {}
    protected void onMainResume() {}
    protected void onMainDestroy() {}

    protected void onGLDrawFrame(GL10 gl) {}
    protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // Singletons will always miss first 'onGLSurfaceChanged' call.

}

回电Godot

从Java调用Godot更困难一些。必须首先知道脚本的实例ID,这是通过调用 get_instance_ID() 在剧本上。这返回一个可以传递给Java的整数。

从Java中使用 calldeferred 与Godot通信的功能。Java最有可能在一个单独的线程中运行,因此调用被延迟:

GodotLib.calldeferred(<instanceid>, "<function>", new Object[]{param1, param2, etc});

Godot将检测到这个单例并在适当的时候初始化它。

故障排除

装载时Godot坠毁

检查 adb logcat 对于可能出现的问题,则:

  • 确保libgodot的android.so在 libs/armeabi 文件夹

  • 检查Java单子中使用的方法只使用简单的Java数据类型,不支持更复杂的数据类型。

未来

Godot有一个实验Java API包装器,它允许使用来自GDScript的整个Java API。

它使用简单,使用方法如下:

class = JavaClassWrapper.wrap(<javaclass as text>)

这很可能还不起作用,如果您想测试它并帮助我们使其正常工作,请在irc.freenode.org上联系我们:godotenengine devel。