Unity 指定時間ローカルプッシュ通知処理を書いてみた Android編
-- 8/26追記 今北工業さんが私の記事のtypoを修正してくださりました〜! こちらも参考にしてくださいm( )m
今月末に引っ越しを控え案件のタスクを残したくないraharuです
さて、前回に引き続きUnityのNative連携のAndro編です。
流れとしてはAlarmManagerで登録
レシーバーで受信したらローカル通知を投げるという事をしたいだけなのにクソはまった。。
※まだAndroidPluginの作成環境が出来てない人はこちらの記事で環境を構築してください。
パッケージ名は自由ですが、
今回はnet.raharu.localnotifypluginです
これあとでAndroidManifestに使うので重要
java側
localNotification.java
package net.raharu.localnotifyplugin; import java.util.Calendar; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.util.Log; import com.unity3d.player.UnityPlayer; public class localNotification { /** * 時間指定でローカル通知を投げる * @param message * @param unixtime * @param primary_key */ public void sendNotification(String message, long unixtime, int primary_key) { Log.i("Unity", "SendNotificationStart"); // インテント作成 Activity activity = UnityPlayer.currentActivity; Context context = activity.getApplicationContext(); Intent intent = new Intent(context, NotificationReceiver.class); //渡す値 intent.putExtra("MESSAGE", message); intent.putExtra("PRIMARY_KEY", primary_key); //10秒後にアラーム(デバック用) Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.add(Calendar.SECOND, 10); PendingIntent sender = PendingIntent.getBroadcast(context, primary_key, intent, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis() , sender); } }
NotificationReceiver.java
package net.raharu.localnotifyplugin; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v4.app.NotificationCompat; /** * レシーバー * * @author raharu */ public class NotificationReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //値の取得 String message = intent.getStringExtra("MESSAGE"); Integer primary_key = intent.getIntExtra("PRIMARY_KEY", 0); // intentからPendingIntentを作成 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); // LargeIcon の Bitmap を生成 final PackageManager pm = context.getPackageManager(); ApplicationInfo applicationInfo = null; try { applicationInfo = pm.getApplicationInfo(context.getPackageName(),PackageManager.GET_META_DATA); } catch (NameNotFoundException e) { e.printStackTrace(); return; } final int appIconResId = applicationInfo.icon; Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(), appIconResId); // NotificationBuilderを作成 NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setContentIntent(pendingIntent); builder.setTicker("通知がとどきました"); //ステータスバーに届くテキスト builder.setSmallIcon(appIconResId); //アイコン builder.setContentTitle("タイトルだよ!!"); // タイトル builder.setContentText(message); // 本文(サブタイトル) builder.setLargeIcon(largeIcon); //開いた時のアイコン builder.setWhen(System.currentTimeMillis()); //通知に表示される時間(※通知時間ではない!) // 通知時の音・バイブ・ライト builder.setDefaults(Notification.DEFAULT_ALL); builder.setAutoCancel(true); // NotificationManagerを取得 NotificationManager manager = (NotificationManager) context.getSystemService(Service.NOTIFICATION_SERVICE); // Notificationを作成して通知 manager.notify(primary_key, builder.build()); } }
このパッケージをjarとしてエクスポートしてAssets/Plugin/Androidの直下に起きます。
Unity側
AndroidMnifest.xmlにレシーバーと権限を追加
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="XXXXXXXXXXXX" android:installLocation="preferExternal" android:theme="@android:style/Theme.NoTitleBar" android:versionCode="1" android:versionName="1.0"> <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true"/> <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name="com.unity3d.player.UnityPlayerNativeActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" /> </activity> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> #ここに通知されるレシーバーを登録する(パッケージ名+クラス名) <receiver android:name="net.raharu.localnotifyplugin.NotificationReceiver" android:process=":remote" /> </application> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="20" /> <uses-feature android:glEsVersion="0x00020000" /> <uses-permission android:name="android.permission.INTERNET" /> #バイブレートの権限追加 <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> </manifest>
こんな感じで呼び出せる
#if UNITY_ANDROID AndroidJavaObject m_plugin = new AndroidJavaObject( "net.raharu.localnotifyplugin.localNotification"); if (m_plugin != null){ m_plugin.Call("sendNotification", "本文だよ!!!!", [unixtime], [unique_id]); } #endif
unixtimeは通知したい時間(今回は強制で10秒後にしてるけども。。)
第三引数はユニークな値を入れるとよし
これで時間指定したローカル通知が届くようになりました。
当たり前の事かも知れないけど一本アプリ作るのに
c# java obj-c phpと4言語扱うのに
mono eclipse xcode vimを言ったり来たりして段々今何言語書いてるのか分からなくなってくる。
ネイティブ連携は面倒くさいね!
参考にさせて頂きました
Unity ローカルプッシュ通知処理を書いてみた iOS編
iOS8からローカルプッシュ通知にもユーザー許可が必要になりました。
今迄のやり方だとローカル通知が遅れなくなってしまったので
起動時に認証ダイアログを表示させるようにします。
まずはAssets/Plugin/iOS以下に
LocalNotificationController.mmを作成します。
ソースはこんな感じで書きます
#import "iPhone_target_Prefix.pch" #import "UnityAppController.h" @interface LocalNotificationController : UnityAppController +(void)load; @end @implementation LocalNotificationController +(void)load { extern const char* AppControllerClassName; AppControllerClassName = "LocalNotificationController"; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { [super application:application didFinishLaunchingWithOptions:launchOptions]; float version = [[[UIDevice currentDevice] systemVersion] floatValue]; if (version >= 8.0) { if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound categories:nil]; [application registerUserNotificationSettings:settings]; } } return YES; } @end
これで実機起動すれば認証ダイアログが出てくるはずです。(iOS8以上)
実際に通知を送ってみます。
using UnityEngine; using System.Collections; public class LocalNotifyScript : MonoBehaviour { void Start () { addLocalPush (); } void addLocalPush () { Debug.Log ("ローカル通知が走ります"); #if UNITY_EDITOR #elif UNITY_ANDROID #else addLocalPushiOS(); #endif } void addLocalPushiOS() { LocalNotification l = new LocalNotification(); l.applicationIconBadgeNumber = 1; l.fireDate = System.DateTime.Now.AddSeconds(10); l.alertBody = "通知テストだよ!"; NotificationServices.ScheduleLocalNotification(l); } }
これを適当なGameObjectにアタッチします。
なかなか資料が見つからず四苦八苦しました。。。
安西先生、ネイティブ連携をサクサク書けるようになりたいです。。
参考にさせていただきましたm( )m
UnityのiOSでAppDelegateに処理を追加する - ほげほげ(仮)
[Unity] iOS8でローカル通知が動かない: ものづくりログ
Unityで作ったiOSアプリにObj-CでPush通知を載せてみた | 丸ノ内テックブログ
UnityでiOSのネイティブコードを呼び出す最も簡単でシンプルな方法 - C# → Objective-C
[備忘録]AppController.mmあたりをいじっている時のUnity4.1.5迄からUnity4.2以上に上げる時の注意 - Qiita
Laravel4 Eloquent ORM SELECTをあれこれ試してみる
前回Createと触り程度をやってみたEloquent ORMですが
今回はもう少し踏み込んで見たいと思います。
クエリを試す
<?php ~~ skip //PK参照 $records = Calendar::find(1); //条件参照 $records = Calendar::where('area_name', 'tokyo')->get(); //条件参照(比較演算子) $records = Calendar::where('id', '<=', 2)->get(); //条件参照(LIKE) $records = Calendar::where('area_name', 'LIKE', "%kyo%")->get(); //条件参照(IN) $records = Calendar::whereIn('area_name', array('tokyo', 'aomori'))->get(); //条件参照(OR) $records = Calendar::whereOr('area_name', array('tokyo', 'aomori'))->get(); //Order $records = Calendar::where('area_name', 'tokyo')->orderBy('id', 'DESC')->get(); //Where最初とは限らない $records = Calendar::groupBy('area_name')->get(); //OR句のネストだとこうなる(ちょっと複雑にしてみた) //select `id` from `calendar` where `calendar`.`deleted_at` is null and (`id` <= ? or `id` >= ?) and `area_name` = ? order by `id` desc $records = Calendar::select('id') ->where(function($query) { $query->where('id', '<=', 10); $query->orWhere('id', '>=', 50); }) ->where('area_name', 'tokyo') ->orderBy('id', "DESC") ->get(); // クエリログを確認する var_dump(DB::getQueryLog()); //JSON形式で表示 var_dump( Response::json($records));
これらが出来ればもう参照クエリは制覇したも当然です(基本JOINは使わないし)
特に困る様な事も無さそうです。
Laravel4 Eloquent ORMを試してみる
ドキュメントもしっかりしてるし考えられて作られているなーと思うLaravelですが、
日本で全くといって良いほど流行ってねー()
2年前からあるはずなのになんでこんなに過疎ってるんでしょうかね。。
もっと流行っても良いと思うんですけどね、ステッカー欲しいです
とま今回は個人プロジェクトのバック用に使用しているだけなので
別に流行ってようが流行ってなかろうが関係無いんですけどね。
今回はEloquent ORMを試します。
前回同様適当なテーブルを作成しておきます。
<?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateCalendarTable extends Migration { >.../** >... * Run the migrations. >... * >... * @return void >... */ >...public function up() >...{ Schema::create('calendar', function($table){ $table->increments('id'); $table->string('area_name', 32); $table->date('onair_date'); $table->time('onair_time'); $table->string('title', 128); $table->string('url', 256); $table->string('station', 64); $table->string('state', 64); $table->string('episode', 32)->nullable(); $table->string('week_name', 32); $table->timestamps(); $table->softDeletes(); }); >...} >.../** >... * Reverse the migrations. >... * >... * @return void >... */ >...public function down() >...{ Schema::drop('calendar'); >...} }
deleteは論理削除で行いたいのでsoftDeletesを追加しています。
これをマイグレートしてテーブルを作成しました
このテーブルにレコード追加します 前回の記事では
DB::insert('insert into template (`key`, `value`, `created_at`, `updated_at`) values(?, ?, ?, ?)', array('template.v1', 'hogehogehogehoge', $now_timestamp, $now_timestamp));
こんな書き方だったのですが、今回はO/Rマッパーを使うのでそこら辺りもいい感じに
出来ると期待しています。
Eloquentモデルを作成する
app/models/以下にモデルの受け皿となるクラスを作成します。
(これを作成するartisanコマンドないのか。。。)
<?php class Calendar extends Eloquent { // SoftDelete use SoftDeletingTrait; protected $dates = ['deleted_at']; //テーブル名 protected $table = 'calendar'; /** * createメソッド利用時に、入力を受け付けないカラムの指定 */ protected $guarded = array('id'); }
意外にprotected $guarded = array('id');
が重要でidはオートインクリメントされているのでインサート時に指定しなかったわけだが
それだとエラーにされるという落とし穴がある。
レコード作成例
<?php ~~skip $record = new Calendar; $record->area_name = $area_name; $record->title = $item->title; $record->url = $item->url; $record->onair_time = $item->time; $record->station = $item->station; $record->state = $item->state; $record->onair_date = $item->next; $record->week_name = $item->week; Calendar::firstOrCreate($record->getAttributes());
$record = new Calendar;
でテーブル本体をインスタンス化してカラムに値を追加しています
実際は$record->save()だけで事が済むんですが同一レコードを入れたく無かったので
今回はfirstOrCreateを使用しています
ばっちり入りました
これでSQLをガチで書く様な事をしなくてすっきり書けます。
いい感じですね、ベンチマーク取ってどの程度負荷に耐えられるのか試してみたくなりました。
次は参照やあれこれやってみたいと思っています。
Laravel4 DB操作とマイグレーションを試す
とりあえずサーバーにmysqlをインストールしておきます。
設定を行う
app/config/database.phpのmysql配列を変更する
'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'dbname', 'username' => 'username', 'password' => 'password', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ),
変更箇所は自分の環境の場合は
databaseとusernameとpassword
databaseは適当に作っておきます。
マイグレーションファイルを作成する
$ php artisan migrate:make create_template_table
今回はテーブルのひな形テーブルを作成します。
app/database/migrations/2015_01_06_184420_create_template_table.php
のパスにファイルが作成されました。
これを修正します。
<?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateTemplateTable extends Migration { >.../** >... * Run the migrations. >... * >... * @return void >... */ >...public function up() >...{ Schema::create('template', function($table){ $table->increments('id'); $table->string('key', 128)->unique(); $table->string('value', 256)->nullable(); $table->text('data')->nullable(); $table->timestamps(); $table->timestamp('deleted_at')->nullable(); $table->enum('active', array('0', '1'))->default('1'); }); >...} >.../** >... * Reverse the migrations. >... * >... * @return void >... */ >...public function down() >...{ Schema::drop('template'); >...} }
Schemaのコマンドは
DB:スキーマビルダー
に書かれています、ほとんど悩む事なくつくれました
マイグレーション実行
$ php artisan migrate
DBをみてみると
テーブルができました。
マイグレートのコマンドは以下の通り
php artisan list | grep migrate migrate Run the database migrations migrate migrate:install Create the migration repository migrate:make Create a new migration file migrate:publish Publish a package's migrations to the application migrate:refresh Reset and re-run all migrations migrate:reset Rollback all database migrations migrate:rollback Rollback the last database migration
直感的な動きをしますので各コマンドを試してみるのが良いと思います。
インサートしてみる
$now_timestamp = date("Y-m-d h:i:s"); DB::insert('insert into template (`key`, `value`, `created_at`, `updated_at`) values(?, ?, ?, ?)', array('template.v1', 'hogehogehogehoge', $now_timestamp, $now_timestamp));
試しにこんなクエリを作ってみました。 実行してみると
ちゃんと入っています。
Laravel今日一日ためしてみましたが、何かと機能が充実してる感じで使いやすいです。 ドキュメントもしっかり作られているので戸惑う事も少ない良フレームワークだと思います。
次はEloquent ORMを試します。
Laravel4 バッチ処理を書いてみる
ネイティブアプリのバックエンドでLeravelの導入をしようとしているので スケジューラーで動かすことが前提です。
ですのでバッチモードで動かないとお話になりません。
今回はそんな話
コマンドファイルの作成
$ php artisan command:make LoadInformation --command=batch:loadinfo
このコマンドでapp/commands以下に LoadInformation.phpが作成され、コマンド名はbatch:loadinfoとなります。
コマンド名は後から変更出来ます。
コマンドの登録
app/start/artisan.phpにさっき作ったコマンドを登録します。
Artisan::add(new LoadInformationi());
コマンドが登録されたか確認します
$ php artisan list ~~ skip batch batch:loadinfo コマンドラインからの情報ロードバッチ
こんな感じでlistに表示されました。
実行してみる
$ php artisan batch:loadinfo [RuntimeException] Not enough arguments. batch:loadinfo [--exampl[="..."]] example
初期作成のバッチは必ず引数とオプション入れろと起こられます。 引数は後にしたくてとりあえず動く所が見たいので app/commands/LoadInformation.phpの以下をコメントアウト
~~ skip // array('example', InputArgument::REQUIRED, 'An example argument.'), ~~ skip // array('exampl', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
これでエラーが出ずに抜けるはずです
出力を試す
public function fire()以下がexecuteメソッドなのでそこに記述します。
public function fire() { //出力系 var_dump('出力テスト'); $this->info('標準出力'); $this->error('エラー出力'); }
再度実行
$ php artisan batch:loadinfo string(15) "出力テスト" 標準出力 エラー出力
なるほどここまでくればあとはごにょごにょ試せば大体書けそうです早速バッチを作成してみる事にします
ここをみながらやってみましょう CLI:開発
補足
php artisan command:make TestCommand --path=app/batch --namespace=Batch --command=batch:test
例えばこんなコマンド任意な場所に作成したコマンドをapp/start/artisan.php にどうやって登録するのか、、イマイチ分からないので次に試したいと思う
Laravel4始めました
去年あたりから巷で人気のPHPフレームワーク
プロジェクトを属人化させないようにもちょっと触ってみたい所だったのでやってみようと思う。
環境
VPS | サクラVPS |
---|---|
OS | CentOS release 6.3 |
Apache | Apache/2.2.15 |
PHP | PHP 5.5.19 |
事前にPHPのバージョンを上げる必要がある。
導入
こちらを参考にさせていただきました。
多少の注意点としては
①Error in exception handler.と言われたら
app/storageにパーミションが足りないと言われているので その際には 権限を付与してあげるのが良い。
$ chmod -R 777 app/storage
自分の場合はApacheのDocumentRootにシンボリックリンクを貼っているので
パスの通ったURLにアクセスすれば問題なく表示された。