Androidへの移植

Androidへの移植



この記事の最後で、Android用のポートを作成する計画を発表しました。 ここで、私が遭遇した問題とそれらを解決する方法を説明しようとします。 現時点でのAndroidの体験はちょうど2か月であり、このプラットフォームでは一部のソリューションが危険であるか、受け入れられないことさえあることをすぐに予約したいと思います。

エンジン


エンジン(趣味)は10年間開発中です。
エンジンは完全にC / C ++で記述されており、Androidへの移植を開始する前にiOSとWindowsをサポートしていました。
ロジック、レンダリング、サウンド-すべてC / C ++。


ファイルシステム


Androidへの移植を非常に簡単にした重要な機能は、エンジンのファイルシステムです。

擬似コード:
 class IStream { void setName(string name ) = 0; open() = 0; write() = 0; … = 0; } class FileStream : public IStream {   fopen,fread... POSIX API. } class DataPackStream : public IStream {     .pak  Core::Meta* m_packFileStreamMeta;; /// m_packFileStreamMeta->Create() IStream*         .pak  } 


そのため、エンジン内のファイルの処理はすべてIStreamインターフェイスに基づいており、エンジンアーキテクチャはオブジェクトのファクトリとそのカスタマイズをサポートしています。

コード例:
 Core :: FileStream :: Type()-> setFactoryMeta(DataPack :: DataPackStream :: Type());

 FileStream * filestream1 = FileStream :: Create();
 //新しいFileStream()でも同じことが起こります
 FileStream * filestream2 = FileStream :: CreateExact();

 filestream1はDataPackStreamタイプになります
 filestream2はFileStreamタイプになります


新しいものはなく、すべてが非常に標準的です。

すべてのリソースは.pakファイルで暗号化されているため、Androidシステムの場合、Javaを操作するためにIStreamの独自の実装を作成する必要がありました。

Javaでこのリソースを初期化する
 AssetFileDescriptor RawAssetsDescriptor = this.getApplicationContext()
				 .getResources()。openRawResourceFd(R.raw.data000);
 if(RawAssetsDescriptor!= null)
 {
     FileInputStream fis = RawAssetsDescriptor.createInputStream();
     NativeMethods.dataPackChannel = fis.getChannel();
     NativeMethods.dataPackOffset = RawAssetsDescriptor.getStartOffset();
     NativeMethods.dataPackSize = RawAssetsDescriptor.getLength();
 }


ネイティブクラスは、すべての呼び出しをJavaで開いて、読み取り、再度シークします
クラスAndroidPackStream:パブリックIStream
 {
 // ....
     //例を読む
     size_t読み取り(void *バッファー、size_tサイズ、size_tカウント)
     {
       if(JavaHelpers :: m_pClass)
       {
         jmethodID mid = JavaHelpers :: GetEnv()-> GetStaticMethodID(JavaHelpers :: m_pClass、 "freadDataPack"、 "(I)I");
         int res = JavaHelpers :: GetEnv()-> CallStaticIntMethod(JavaHelpers :: m_pClass、mid、(int)size * count);
	 jfieldID field = JavaHelpers :: GetEnv()-> GetStaticFieldID(JavaHelpers :: m_pClass、 "byteBuffer"、 "Ljava / nio / MappedByteBuffer;");
	 jobject obj = JavaHelpers :: GetEnv()-> GetStaticObjectField(JavaHelpers :: m_pClass、フィールド);
	 uint8_t * pData =(uint8_t *)JavaHelpers :: GetEnv()-> GetDirectBufferAddress(obj);
	 memcpy(バッファ、pData、サイズ*カウント);
	 JavaHelpers :: GetEnv()-> DeleteLocalRef(obj);
	解像度/サイズを返します。
     }
 }


ネイティブにデータを返すことでこのストリームを読み取るJava実装
 public static int freadDataPack(intカウント)
 {
     long curPos = dataPackChannel.position();
     int countReaded = count;
     byteBuffer = dataPackChannel.map(MapMode.READ_ONLY、dataPackChannel.position()、count);
     byteBuffer.load();
     dataPackChannel.position(curPos + countReaded);
     returnCountReaded;
 }


重要な点-apkコレクターはすべてのリソースを圧縮し、ファイルシステムにあるかのようにファイルを読み取りたいと思います。 .pakファイルがapk内で圧縮されないようにするには、その拡張子を、パック時にこれらのファイルを圧縮しないようにパッカーに伝えるものの1つに変更する必要があります(詳細はponystyle.com/blog/2010/03/26/dealing-with-asset -compression-in-android-apps )。 .imyを選択しました。
この方法でのリソースのダウンロードは非常に高速です。たとえば、Kindle FireはiPadよりも高速です1
多くのデータがない場合、このようなフェイントを上げることができるというラインストーンを言います。
大量のデータの場合-データを内部メディアに解凍し(たとえば、最初に起動したとき)、fopen fread関数を使用して直接使用できます(私の場合は、変更されていないFileStreamを使用)など。


WindowsおよびiOSの場合、OpenALが使用されました。 Android用OpenALは、 pielot.org / 2010/12/14 / openal-on-androidのおかげでコンパイルされました。 すぐには獲得できませんでしたが、ウェブサイトのコメントに記載されている修正を行った後のみです。
AndroidのアセンブリはArm v7のみでコンパイルされます-Arm v6 OpenALのポートのアセンブリは時々遅延を引き起こすため、iOS OpenALではミキサーはより速く、遅延なく動作します(iPod Touch 2GなどのArmV6でも)。

C / C ++のネイティブコードとの相互作用

非常に単純なクラスの束が、プラットフォーム依存の実装への呼び出しを処理します。
擬似コード:

クラスIPlatfomCommandFeedback
 {
     void onResponse(string&);
 };
クラスIPlatfomCommand
 {
    文字列実行(文字列とコマンド、IPlatfomCommandFeedback * feebback);
 };


IOSにはObjective-Cに独自の実装があり、AndroidにはJNI-> Javaに独自の実装があります。

レンダリング

アクティブな部分はOpenGLを使用して機能します。Androidの最小限の変更が加えられています。 後で判明したように、これは十分ではありませんでした。 実際、WindowsおよびiOSでは、アプリケーションがバックグラウンドに移行してもテクスチャは失われませんが、Androidでは常に発生します。 エンジンにはすでにテクスチャマネージャがあり(主にデバッグ用)、リソースのリロードを追加することは難しくありませんでした。

組立

最初の記事で、私は最初にツールチェーンを使用してiOSをコンパイルし、メイクファイルをカスタマイズしたことを書きました。 これは私にとって便利な場所でした。 Android NDKを使用してビルドするためのターゲットが追加され、Eclipse Builderにステップが追加され、すべてが始まりました。 はい、Android NDKサンプルからビルドシステムを使用できます。 gcc呼び出しに使用されるパラメーターを見つけるためにのみ使用しました。

OpenFenit AdMob

両方のライブラリの統合は問題なく行われました-開発者の指示に従って明らかに

プロガード

ここですべてが多かれ少なかれ明確です-あなたはあなたのJNIネイティブバインドがobuscheyatsyaではないことに注意する必要があります

開発ツール

Iron:Kindle Fire、および友人のタブレットと携帯電話(テスト用)。
ソフトウェア:プラグイン付きEclipse

衝撃番号1

AndroidマーケットはAppStoreではありません。 そこではすべてが異なります。 新しいカテゴリはありません。
比較のために、リリースの最初の日に、AppStoreで800回以上のダウンロードがあり、2000年以降のAndoid Marketで、公式の最初の100回のダウンロードは3日目にのみ受信されました。 両方のプラットフォームのプロモーション活動は同じでした

ショック番号2

アプリケーションが無料の場合は、apkを自由に配布でき、誰でも任意のソースからこのアプリケーションをインストールできます。 これを行わない場合、他の人があなたのためにそれを行います。

ショック数3

デバイスの獣姦は素晴らしいです。 それぞれ問題の数。

アマゾン

Android向けAmazon AppStoreでのレビュープロセスには1週間かかり、さらにKindle FireのAppStoreリストにアプリケーションが表示されるまでさらに数日かかります。 ダウンロード数とスピーカーはAndroidマーケットに対応しています

広告

Good Corporationへの憎悪の光線-すでに1週間、広告バナーがアップストリームに送信されました。 まだ沈黙。

お金

現時点では、iOSバージョンがもたらすお金の量(私はゲームでの広告のみを思い出します)は、Androidのバージョンの40倍です。 比較が正しくないことは明らかであり、1日あたりのレギュラープレイヤーの数が安定するまで、少なくとも数か月待つ必要があります。

更新:サウンドセクションで、ArmV7 Androidデバイスのみのビルドの理由を説明しました。

Source: https://habr.com/ru/post/J139293/


All Articles