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. Quick Start ウィンドウで Projects をクリックし、Examples タブを選択します。Coin の例の横にある ダウンロード をクリックします。

  2. <KanziWorkspace>/Examples/Coin でアプリケーションのコピーを作成します。

  3. Kanzi Studio で、Kanzi Studio プロジェクト Tool_project/Coin.proj.kzm を開きます。メインメニューで、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'
      
    • アプリケーションの Java 言語レベルを 11 以上に設定してください。

      android {
          ...
          compileOptions {
              sourceCompatibility JavaVersion.VERSION_11
              targetCompatibility JavaVersion.VERSION_11
          }
      
  6. app/src/main/res/layout/main.xml で、ビュータイプを変更します。

    com.rightware.kanzi.KanziView
    

    終点

    com.rightware.kanzi.KanziSurfaceView
    
  7. アプリケーションのアクティビティにおいて app/src/main/java/com/rightware/kanzi/coin/Coin.java:

    • onCreate(Bundle icicle) からアクティビティライフサイクルの登録を削除します。Kanzi Android framework (droidfw) はビューのライフサイクルコールバックを自動的に追跡します。

      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);
      }
      

      終点

      @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ファイルを1つを除いて削除することができます。アプリケーションをビルドするには、CMakeは1つの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がありません。アクティビティのライフサイクルコールバックを手動で登録する必要はありません。

    解決策: この呼び出しを削除できます。

  • エラー:

    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 の sourceCompatibility と targetCompatibility を JavaVersion.VERSION_11 以上に設定します。

  • エラー:

    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::kzdroidfw ではなく Kanzi::kzappfw にリンクしています。

    解決策: 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 をリンクされたターゲットのリストに追加します。