从 Kanzi application framework (appfw) 迁移到 Kanzi Android framework (droidfw)。

请按照以下说明将 Kanzi 应用程序从 Kanzi application framework (appfw) 迁移到 Kanzi Android framework (droidfw)。

例如,要将 Coin 示例应用程序从 Kanzi application framework (appfw) 迁移到 Kanzi Android framework (droidfw):

  1. 在 Kanzi Studio Quick Start 窗口中,点击 Examples。在 Coin 示例旁边,点击 下载。

  2. 在 <KanziWorkspace>/Examples/Coin 处复制该应用程序。

  3. 在 Kanzi Studio 中,打开 Kanzi Studio 项目 Tool_project/Coin.kzproj。在主菜单中,选择 File > Export > Export KZB。

    ../../../_images/export-kzb-binary.png
  4. 在 Android Studio 中,打开 Application/configs/platforms/android_gradle 目录中的项目。

  5. 在 app/build.gradle:

    • 将应用程序 minSdk 设置为 26 或更高。这是 Kanzi Android framework (droidfw) 所需的最低 SDK 版本。

    • 配置应用程序以使用 Kanzi Android framework (droidfw)。替换

      dependencies {
          ...
          implementation 'com.rightware.kanzi:kanziruntime@aar'
      

      通过

      dependencies {
          ...
          implementation 'com.rightware.kanzi:kanziruntime-droidfw@aar'
      
    • 将 kzjava 库添加为依赖项。

      dependencies {
          ...
          implementation 'com.rightware.kanzi:kzjava@aar'
      
    • 将 Kanzi Android framework (droidfw) 设置为 Java 版本 8 或更新版本。

      android {
          ...
          compileOptions {
              sourceCompatibility JavaVersion.VERSION_1_8
              targetCompatibility JavaVersion.VERSION_1_8
          }
      
  6. 在 app/src/main/res/layout/main.xml 中,将视图类型从

    com.rightware.kanzi.KanziView
    

    至 (To)

    com.rightware.kanzi.KanziSurfaceView
    
  7. 在应用程序 app/src/main/java/com/rightware/kanzi/coin/Coin.java 的活动中:

    • 从 onCreate(Bundle icicle) 中移除 Activity 生命周期注册。Kanzi Android framework (droidfw) 会自动跟踪 View 生命周期回调。

      mView = findViewById(R.id.kanzicontent);
      mView.registerLifecycle(getLifecycle());
      
    • 在 onCreate(Bundle icicle) 中加载 kzb 文件,并在此 KanziSurfaceView 中设置您要加载的预设。在此项目中,您使用默认预设 StartupPrefab。

      在 Kanzi application framework (appfw) 中,本机应用程序代码加载了 kzb 文件,而在 Kanzi Android framework (droidfw) 中,则不使用本机应用程序代码。

      mView = findViewById(R.id.kanzicontent);
      mView.setKzbPathList(new String[]{"Coin.kzb.cfg"});
      mView.setStartupPrefabUrl("kzb://coin/StartupPrefab");
      
    • 将处理屏幕方向更改的方法从

      @Override
      public void onConfigurationChanged(Configuration newConfig)
      {
          super.onConfigurationChanged(newConfig);
          mView.setOrientation(newConfig.orientation);
      }
      

      至 (To)

      @Override
      public void onConfigurationChanged(Configuration newConfig)
      {
          super.onConfigurationChanged(newConfig);
          mView.handleOrientationChange(newConfig.orientation);
      }
      
  8. 在 CMake 配置 Application/CMakeLists.txt 中:

    • 替换 (Replace)

      if(ANDROID)
          target_link_libraries(Coin -Wl,--whole-archive Kanzi::kzappfw -Wl,--no-whole-archive)
      

      通过

      if(ANDROID)
          target_link_libraries(Coin -Wl,--whole-archive Kanzi::kzdroidfw -Wl,--no-whole-archive)
      
    • 将 kzinterop 和 kzjava 库链接到应用程序。替换

      target_link_libraries(Coin Kanzi::kzui Kanzi::kzcoreui)
      

      通过

      target_link_libraries(Coin Kanzi::kzui Kanzi::kzcoreui Kanzi::kzinterop Kanzi::kzjava)
      

现在应用程序使用 Kanzi Android framework (droidfw),您可以在您的 Android 设备上运行它。

迁移应用程序代码

在您将应用程序从 Kanzi application framework (appfw) 迁移到 Kanzi Android framework (droidfw) 之后,该应用程序中的 C++ 代码将不再使用。您可以将应用程序的现有 C++ 代码迁移到 Java 应用程序或插件代码,或者将功能重构为 C++ Kanzi Engine 插件。由于 Java API 并未实现完整的 Kanzi Engine API,因此应用程序代码的迁移方法取决于您的应用程序的功能。

您可以删除除一个 cpp 文件之外的所有文件。要构建应用程序,CMake 需要一个 cpp 文件,即使该文件是空的。 例如,删除 Application/src/coin.cpp 的内容。

例如,要使用 Java 在 Coin 示例中显示 Text Block 节点中的帧时间:

  1. 在 app/src/main/java/com/rightware/kanzi/coin/Coin.java 中,在应用程序活动中,向 Coin 类添加一个方法:

    void updateFrameTime(Duration duration)
    {
        TextBlock2D frameTime = mView.getRoot().lookupNode("#FrameTime");
        frameTime.setText("Frame time: " + duration.toMillis() + " ms");
    }
    
  2. 在 onCreate(Bundle icicle) 中,添加一个主循环调度任务以在每一帧执行该方法:

    KanziRuntime.Reference runtimeRef = KanziRuntime.acquire(this);
    
    mView.addListener(new KanziViewListener() {
         @Override
         public void onStartupPrefabLoaded(View view, Domain domain) {
             runtimeRef.get().getDomain().getMainLoopScheduler().appendTask(
                     MainLoopScheduler.UserStage,
                     "Update Frame Time",
                     TaskRecurrence.Recurring, duration -> updateFrameTime(duration));
         }
    });
    

当您进行更改时,这就是 app/src/main/java/com/rightware/kanzi/coin/Coin.java 的样子:

package com.rightware.kanzi.coin;

import android.content.res.Configuration;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;

import android.view.View;
import android.view.WindowManager;

import com.rightware.kanzi.Domain;
import com.rightware.kanzi.KanziRuntime;
import com.rightware.kanzi.KanziView;
import com.rightware.kanzi.KanziViewListener;
import com.rightware.kanzi.MainLoopScheduler;
import com.rightware.kanzi.TaskRecurrence;
import com.rightware.kanzi.TextBlock2D;

import java.time.Duration;

public class Coin extends FragmentActivity
{
    private static final String TAG = "Coin";
    private KanziView mView = null;

    @Override
    protected void onCreate(Bundle icicle)
    {
        setContentView(R.layout.main);

        mView = findViewById(R.id.kanzicontent);
        mView.setKzbPathList(new String[]{"Coin.kzb.cfg"});
        mView.setStartupPrefabUrl("kzb://coin/StartupPrefab");

        // Force the screen to stay on when this app is on front (no need to clear).
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        KanziRuntime.Reference runtimeRef = KanziRuntime.acquire(this);

        mView.addListener(new KanziViewListener() {
            @Override
            public void onStartupPrefabLoaded(View view, Domain domain) {
                runtimeRef.get().getDomain().getMainLoopScheduler().appendTask(
                        MainLoopScheduler.UserStage,
                        "Update Frame Time",
                        TaskRecurrence.Recurring, duration -> updateFrameTime(duration));
            }
        });

        super.onCreate(icicle);
    }

    void updateFrameTime(Duration duration)
    {
        TextBlock2D frameTime = mView.getRoot().lookupNode("#FrameTime");
        frameTime.setText("Frame time: " + duration.toMillis() + " ms");
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
        mView.handleOrientationChange(newConfig.orientation);
    }
}

排除问题

以下是将 Kanzi 应用程序从 Kanzi application framework (appfw) 移植到 Kanzi Android framework (droidfw) 时可能遇到的一些最常见问题。

  • 错误:

    <KanziWorkspace>\Projects\CoinPort\Application\configs\platforms\android_gradle\app\src\main\java\com\rightware\kanzi\coin\Coin.java:21: error: cannot find symbol
        mView.registerLifecycle(getLifecycle());
             ^
    symbol:   method registerLifecycle(Lifecycle)
    location: variable mView of type KanziView
    

    原因:Kanzi Android framework (droidfw) 没有此 API。您不必手动注册 Activity 生命周期回调。

    解决方案:您可以删除此调用。

  • 错误:

    7961-7961/com.rightware.kanzi.coin E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.rightware.kanzi.coin, PID: 7961
        java.lang.NoSuchMethodError: No static method metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; in class Ljava/lang/invoke/LambdaMetafactory; or its super classes (declaration of 'java.lang.invoke.LambdaMetafactory' appears in /apex/com.android.art/javalib/core-oj.jar)
             at com.rightware.kanzi.KanziViewAdapter.handleAttachedToWindow(KanziViewAdapter.java:274)
    

    原因:您的应用程序不符合 Kanzi Android framework (droidfw) 的最低 Java 语言版本要求。

    解决方案:在 app/build.gradle 中,将 compileOptions 设置为 Java 版本 8 或更新版本。

  • 错误:

    9136-9136/? E/ware.kanzi.coin: No implementation found for long com.rightware.kanzi.KanziRuntime.nCreate(android.content.Context) (tried Java_com_rightware_kanzi_KanziRuntime_nCreate and Java_com_rightware_kanzi_KanziRuntime_nCreate__Landroid_content_Context_2)
    9136-9136/? E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.rightware.kanzi.coin, PID: 9136
        java.lang.UnsatisfiedLinkError: No implementation found for long com.rightware.kanzi.KanziRuntime.nCreate(android.content.Context) (tried Java_com_rightware_kanzi_KanziRuntime_nCreate and Java_com_rightware_kanzi_KanziRuntime_nCreate__Landroid_content_Context_2)
          at com.rightware.kanzi.KanziRuntime.nCreate(Native Method)
          at com.rightware.kanzi.KanziRuntime.<init>(KanziRuntime.java:43)
          at com.rightware.kanzi.KanziRuntime.getOrCreateInstance(KanziRuntime.java:195)
          at com.rightware.kanzi.KanziRuntime.acquire(KanziRuntime.java:67)
          at com.rightware.kanzi.coin.Coin.onCreate(Coin.java:30)
    

    原因:您的应用程序链接到 Kanzi::kzappfw 而不是 Kanzi::kzdroidfw。

    解决方案:在 Application/CMakeLists.txt 中,将链接从 Kanzi::kzappfw 更改为 Kanzi::kzdroidfw。

  • 错误:

    5629-5629/? E/ware.kanzi.coin: No implementation found for long com.rightware.kanzi.mathJNI.new_ColorRGBA__SWIG_3(float, float, float, float) (tried Java_com_rightware_kanzi_mathJNI_new_1ColorRGBA_1_1SWIG_13 and Java_com_rightware_kanzi_mathJNI_new_1ColorRGBA_1_1SWIG_13__FFFF)
    5629-5629/? D/AndroidRuntime: Shutting down VM
    
    --------- beginning of crash
    5629-5629/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.rightware.kanzi.coin, PID: 5629
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rightware.kanzi.coin/com.rightware.kanzi.coin.Coin}: android.view.InflateException: Binary XML file line #6 in com.rightware.kanzi.coin:layout/main: Binary XML file line #6 in com.rightware.kanzi.coin:layout/main: Error inflating class com.rightware.kanzi.KanziSurfaceView
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4166)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4312)
        ...
    

    原因:应用程序找不到 Kanzi::kzjava 的本机支持。

    解决方案:在 Application/CMakeLists.txt 中将 Kanzi::kzinterop Kanzi::kzjava 添加到链接目标列表中。