× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。 |
androidでtwitter4jを使っていて、以下のエラーが出て投稿できないときがあった
認証は正常にできるが、投稿する時に例外が発生して以下のようになる
コードを追いかけてみると、トークンやトークンシークレットは正しい値でリクエストを投げている アプリ管理ページhttps://apps.twitter.com/app/ で TestOAuthを試してみると、なんか違うトークンとシークレットでテストしている そこで、管理ページからトークンとシークレットを再生成(Regenerate)。 アプリも一度削除して再度実行 するとできた どうやら、アプリ管理ページから作成するとき、間違えて違うアカウントで登録したので 別のアカウントでログインして再度登録したのだが このとき、古い方のトークン情報が残っているかなんかしたのだろう ツイッター側のサイトがどういう作りをしているのか知らないが… PR |
作成はだいぶ楽である
公式ドキュメント メッセージの他、自由にデータ(payload)を含めて送信できる SDKを入れ、permissionをmanifestに書き、google-services.json 入れたらもうそれだけで届くようになるはず。 ・起動中にpush通知を受け取った場合 FirebaseMessagingService クラスを継承し onMessageReceived(RemoteMessage remoteMessage) メソッドをオーバーライドする。この関数が呼び出される メッセージ本文は remoteMessage.getNotification().getBody() データpayloadは Map<String, String> data = remoteMessage.getData(); となる。data.get("key") みたいな感じで取得。 ・バックグラウンドでpush通知を受け取った場合 受け取った瞬間にアプリ内のどこかのコードが走るわけではない(たぶん) push通知から起動した場合、iOSのように特別なメソッドが呼び出されることはないが、 MainActivity::onStart()内で、getIntent()をすることにより、どう起動されたかがある程度判別可能。
という感じで取得できる。 |
iOSでローカル通知と呼んでいるものと同等のことをAndroidで行おうとする場合
・AlarmManager 指定時刻に処理を発動させる機能を持つクラス 自身のアプリがバックグラウンドにいても問題ない AlarmManager を作成する。 指定すべき事柄は大きく2つ 1. 時刻 発動させたい時刻。long型で、1970/1/1 からのミリ秒 2. 内容 発動させたい内容。 つまり、指定のメッセージで通知を実行するということ Intent型。起動すべきクラスの指定と(後述)、extraに随時データを格納する(メッセージ本文など) AlarmManager が発動したのを受け取るためには BroadcastReceiver を継承し onReceive() を実装する(仮にAlarmReceiverクラスとする) かつ、AndroidManifest.xmlにも記述を行う ・AlarmReceiver::onReceive() で行う内容 Notification.notifyを行う つまり、通知を送信 指定すべき事柄は ・表示内容 通知のタイトル、テキスト、アイコンなど テキストなど、毎回変わるような事柄は AlarmManager から伝達してもらうのが良い onReceiveの引数にintentがあるので、intent.getExtra()などする ・タップ時の挙動 通知をタップした時に実行させる内容 つまり、自身のアプリの起動 Intent型 自身のMainActivity クラスを引数に指定しておけば良い |
前回の記事と基本は同じ
COCOS_CONSOLE_ROOT 以下の plugins/new_project/new_project.py CCPluginNewクラス に書いてある テンプレートとなるプロジェクトは $ COCOS_TEMPLATES_ROOT/cpp-template-default である。他にもjs-templateやlua-templateなどがある ここのディレクトリをコピーして作っている (ただし、cocos-project-template.jsonを除く) プロジェクトの PROJECT_DIR/cocos は、SDKから持ってくる。 大元は、cocos2d-x-v.v/ の直下。 ただし、全部をコピーするわけではない。(tests/ とか setup.py とかはいらない) どのファイルをコピーするかは、 cocos2d-x-v.v/templates/cocos2dx_files.json に書いてある。 "common", "cpp", "js", "lua" とそれぞれ書いてある。cppの場合、"common"と"cpp"のファイル群がコピーされる その他のディレクトリは このcpp-template-default からコピーしてきている |
PROJ_DIR/proj.android-studio
の中で、 $ cocos compile -p android --android-studio を実行する。 この時、どう処理が流れるのかを調べた $ which cocos の場所。 COCOS_CONSOLE_ROOT ディレクトリ配下にある。 cocos はシェルスクリプトで、 同じディレクトリにある cocos.py を実行している cocos.py はpythonスクリプトで 引数に応じたプラグインを実行する プラグインの設定ファイルは、これも同じディレクトリにある cocos2d.ini に書いてある。 コンパイルするためのプラグインは以下の記述。
ファイル名.クラス名となっている。 プラグインは、 COCOS_CONSOLE_ROOT/../plugins にある コンパイル系のプラグインは project_compile ディレクトリ下にあり project_compile.py ファイルのCCPluginCompileクラスになる。 |
Android5.0から、VMが変わった(Darvik -> ART)
その為、過去のコードだと実行時例外がポンポン発生するように 以下のページをよく見て 公式 JNIはベンダーに依存しない。 動的にshared libraryをロードする。 時に扱いづらいが、概ね効率的だ。 JNIには、2つの重要なデータ構造がある JavaVM JNIEnv どちらも、関数テーブルやメンバー関数へのポインタを保持するクラス。 JavaVMクラスは、"invocation interface" functions を提供し、それを使ってJavaVMクラスを生成、破棄できる 理屈的には、JavaVMクラスはプロセスごとに1つ持たせることができるが、Androidは1つしか許可していない JNIEnvクラスは、JNIのほとんどのメソッドを提供している ネイティブ関数呼び出しは、必ず第1引数がJNIEnvになる JNIEnvはスレッド固有に保持する為、スレッド間共有は不可 どうしても必要な場合は、JavaVMの方を共有し、JavaVM.GetEnv()で取得すること CとC++では、JavaVM,JNIEnvの定義が異なる。 jni.hの中身を見るとわかる。 C/C++が混在する場合、ヘッダファイルからjni.hをインクルードするときは要注意 スレッドについて スレッドとは、Linuxスレッドである。 通常はコード上から作成する(java.lang.Thread.start)。 それ以外の手で作られたスレッドの場合、JNIに明示的にアタッチする必要がある(AttachCurrentThread または AttachCurrentThreadAsDaemon関数。なおすでにアタッチ済みのスレッドに対してAttachCurrentThreadを実行しても、何も起こらない)。 そうしないと、そのスレッドにはJNIEnvが生成されず、JNI呼び出しができない。 ネイティブコードからJavaオブジェクトのフィールドにアクセスする場合 FindClass GetFieldID GetIntField の順に使用する メソッドを呼び出す場合 FindClass GetMethodID の順に使用する IDとは通常ポインタのことである。 文字列比較によって検索している。最初は検索するので遅いが、2度目以降は早い はじめに一度検索しておき、結果をキャッシュしておくことは有効だ クラス参照は、クラスがアンロードされるまでは保証される。クラスがアンロードされることは滅多にないが、Androidでは起きうる。ClassLoaderに関連づいているクラスが全てガベージコレクトされた時にアンロードされる。 jclass オブジェクトは、クラス参照である フィールドやメソッドのIDをキャッシュし、クラスがアンロード&リロードされた時に再キャッシュする正しいコードは以下
LocalReference と GlobalReference ネイティブのメソッドに引数として渡ってくる変数は、ローカル参照 そのメソッドが終了すると向こうになる。普通のローカル変数と同じ。(参照元のJavaオブジェクトが生存していても、参照は無効になる) jobject の子クラスである jclass, jstring, jarray などは全てこれ。 グローバル参照は、明示的に削除しない限りずっと参照を保持し続ける 使用例
まずローカル参照を取得し、それをグローバル参照に変換する。 ローカル参照かグローバル参照かで型が変わるわけではない。 全てのJNIメソッドは、ローカル参照もグローバル参照も引数として受け付ける(型が同じだから当然だろう)。 複数の参照が同じオブジェクトを指しているかどうかを判定するには、IsSameObject メソッドを使用すること。==で判定してはいけない。 jfieldIDとjmethodIDは、オブジェクトへの参照ではないため、NewGlobalRefしてはいけない GetStringUTFChars や GetByteArrayElementsも同様である ローカル参照は、明示的にdeleteする必要がある。 ローカル参照が自動的にdeleteされるのは、スレッドが削除された時である。 UTFについて JavaはUTF16を使っている。 JNIはM-UTF8も対応している M-UTF8についてはこちら参照。簡単に言うとJava独自のUTF8。 M-UTF8は、0x0000を0xc0, 0x80という2文字に変換する。 これの利点は、通常のC文字列同様、NULL文字(0x00)を文字列の終端として扱うことができる。(0x0000のままだと、この文字をC文字列終端と認識してしまうから) 欠点は、UTF8からの変換の手間が必要な事。 可能なら、UTF16を使うのが早い。 GetStringCharsは、jstringをUnicode配列に変換する GetStringUTFChars は、jstringをMUTF8に変換する NewStringUTFに渡す文字列は、MUTF8でないといけない。 ここが要注意。ASCII文字列しかないとわかっていれば良いが、そうでなければ変換をする事 でないと、内部でUTF16変換した時、望んでいない結果になる 例外について 例外処理を怠ると、実行時エラーで落とされる
など。 |
前回は、初めて動かしたのでAndroidStudio周りの設定などを色々やった
今回、それが住んでいるものとして、 より簡潔に起動した時の手順 まず、AndroidStudioを開き、 File -> New -> Import Project から cocosプロジェクトのproj.android-studio/ディレクトリを指定して開く build.gradle apps/build.gradle apps/AndroidManifest.xml などを修正 Firebaseに対応するので(参考) Firebaseからgoogle-service.jsonをダウンロード、 apps/ディレクトリに配置(置き換え) この公式ページを参考に、Firebase周りの設定を行う サンプルコードはここ この辺りを見て色々コピー。 build.gradleをSyncすると、 failed to resolve firebase-xxx:v.v.v とか出ることがあるが SDK ManagerでSDKやGoogle Play Services, Google Repositoryなどをアップデートすれば良い。 |
Transformクラスのメソッド
SetSiblingIndex(int) GetSiblingIndex(int) を使う。 数値が大きいほど手前に表示される |
Awakeは、そのオブジェクトが生成された時に呼び出される
コード中からInstantiateされた時などは、その場で呼び出される シーン上に初めから配置されていた場合は、起動直後に呼び出される …とは限らない! 【activeでない】場合は、シーン上にあっても呼び出されない。 初めてactiveになった時に呼び出される。 だから、Awakeの中に書いたことは必ず起動時に呼び出されると思っていてはいけない |