- 投稿日:2019-10-24T23:35:44+09:00
KudanARUnityのサンプルをAndroidで動かす
はじめに
この記事はUnity2018.2.21f1でKudanARUnityを動作させたの備忘録です。
今回はサンプル動作までを記載します。動作環境
Unity2018.2.21f1
KudanARUnity V1.6.0
Android Studio v3.5.1
Glaxy feel SC-04J(Android8.0.0)環境構築
- Unity、Androidのインストールについては割愛します。
- KudanARUnity V1.6.0を以下のページの枠で囲ったリンクからUnityパッケージを取得します。
メールアドレスでの認証が必要で、入力したメールアドレスにダウンロードリンクのURLが添付されています。
ダウンロード先
3. ダウンロードしたKudan-UnityPlugin.zipを任意の箇所に展開します。Unity Editorでのサンプル実行
- UnityのProjectを作成します。
- Unity Editorが起動したら、前項3. で展開したフォルダのKudanARUnity.unitypackageをProjectにD&D、Importします。
- Assets/KudanAR/Samples/KudanSample.unityをダブルクリックし、SampleSceneを開きます。
- HierarchyのKudan Bundle - With UIを開き、InspectorのKudan Tracker(Script)のEditor API Keyに、
Kudanダウンロードページ APIキータブのUnity Editor Key(黒塗り部分)を入力します。(今回は公開されている開発用ライセンスキー使用します)
5. API Keyに、Kudanダウンロードページ APIキータブのKudan AR SDK(黒塗り部分)を入力します。
6. 再生ボタンを押すと、サンプルが実行されます。Assets/KudanAR/Samples/Textures/lego.jpgを表示し、カメラでとらえることで、モデルが表示されます。Android向けのビルドと実行
1. メニューバー File>BuildSettingsを選択し、ビルド設定を出します。
2. 赤枠①で囲ったAndroidを選択し、プラットフォームをAndroidに変更する。
3. 赤枠②で囲ったAdd Open Scenesをクリックし、サンプルシーンをビルド対象に追加する。(すでにチェックが入っているScenes/SampleSceneはチェックを外す)
4. 赤枠③で囲ったplayer Settingsをクリックし、player Settingsを表示する。
4. 赤枠①で囲った、player Settings/Other Settings/Rendering/Multithreaded Renderingのチェックを外します。(理由はイマイチ分かっていませんが、この記事と同じ状況を解決するためにチェックを外しています。)
5. Package NameにKudanダウンロードページ APIキータブのKudan AR SDKのBundle IDを入力します。
(開発者ハブの画像ではeu.kudan.arとなっていますが、画像が古いです)
6. BuildSettingsのSwitch Platformをクリックし、プラットフォームをAndroidへ切り替えます。
7. Edit>Preferencesを開き、External ToolsのAndroid SDK/JDKのPATHを入力する。
8. BuildSettingsのBuild And Runをクリックし、ビルドとアプリファイルの転送実行を行います。
その結果、アプリでAssets/KudanAR/Samples/Textures/lego.jpgをキャプチャするとモデルが表示されます。
おわりに
今回はUnity2018.2.21f1でKudanARUnityのサンプルを動作させました。
次回はオリジナルのマーカー、3Dモデルを表示させます。参考
The Kudan Developer Hub https://www.xlsoft.com/doc/kudan/ja/home_jp/
Kudan + UnityでAndroid向けマーカーレスARを試してみる(1) https://qiita.com/doatodarkness/items/be50fb420ad6ea1c79c0
【Unity初心者向け】Kudan AR SDKを使ったARアプリの開発方法とは? https://blog.codecamp.jp/unity-kudan-ar-sdk
AR KUDANでカメラが起動して居ない https://teratail.com/questions/103107
- 投稿日:2019-10-24T22:55:57+09:00
51歳からのプログラミング 備忘 FusedLocationProviderClientを常駐させる
FusedLocationProviderClientをForegroundSeriviceで常駐させる
androidDeveloperとgoogleApi様を参照してます。
あと、nyan様のサイトも、いっつも参照しています。ありがとうございます。
以下のサンプルコードは、androidのビルドバージョンはapi26以上です。Manifest gradleの確認
Manifest<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <application ... > <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>builed.gradledependencies { ... implementation 'com.google.android.gms:play-services-location:17.0.0'Code
MainActivitypublic class MainActivity extends AppCompatActivity { static TextView textView; static MainActivity mainActivity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Serviceで使うオブジェクトを取得してるよ textView = findViewById(R.id.textView); mainActivity = MainActivity.this; Intent intent = new Intent(this,MyService.class); startForegroundService(intent); } }MyServicepublic class MyService extends Service { TextView textView; FusedLocationProviderClient fusedLocationClient; public MyService() { } @Override public void onCreate() { super.onCreate(); // 位置情報を取り扱う時に使うオブジェクト を取得してるよ textView = MainActivity.textView; fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); } public int onStartCommand(Intent intent, int flags, int startId){ // アプリを常駐させるためにForegorundServiseで通知処理をしまーす! // まずは、通知コンテンツ、チャンネル、重要度の作成ね! Notification notification; NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id"); Intent intentPending = new Intent(this,MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intentPending,0); notification = builder.setSmallIcon(R.drawable.notification_icon) .setContentTitle("sampleApi") .setContentText("sample") .setContentIntent(pendingIntent) .build(); int importance = NotificationManager.IMPORTANCE_LOW; NotificationChannel channel = new NotificationChannel("id","name",importance); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); // ここまでが、通知コンテンツ、チャンネル、重要度の設定でした // 5秒以内に startForeground! 急げ!! startForeground(2,notification); locationManager(); return START_STICKY; } private void locationManager(){ // 定時的に位置を測定する、ていう設定ね LocationRequest request = LocationRequest.create(); request.setInterval(1000*3); request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // ACCESS_FIN_LOCATION は、ユーザーにとって危険のある設定なので // 許可を得るコードが必須です! // では許可チェックをしましょう if(ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ // 許可がなければ許可を求めてみます ActivityCompat.requestPermissions(MainActivity.mainActivity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100); }else{ // 許可があるようなので、位置情報を取得していきます! fusedLocationClient.requestLocationUpdates(request,new LocationCallback(){ @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); // 例示的にlatitudeを表示します String str = String.valueOf(locationResult.getLastLocation().getLatitude()); textView.setText(str); } }, Looper.getMainLooper()); } } public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) { if (requestCode == 100) { // 省略 } } @Override public IBinder onBind(Intent intent) { return null; } }今回も、かなり時間を掛けました。位置情報を常駐的に取得するのって、僕にはハードル高すぎました。このコードを作るまでに約2週間。行ったり来たりを繰り返して、やっとでした~。
今回も亀の歩みですね。
亀の歩みでも、諦めないでもがき続けると、前進できるんだなって感じたよ。
無理かな無理かなと思っても、前進できるんだね。
まだまだ全然実力不足なんだけれど、面白い。すごく楽しい!
- 投稿日:2019-10-24T22:55:57+09:00
51歳からのプログラミング 備忘 FusedLocationProviderClientをForegroundServiceで常駐させる
FusedLocationProviderClientをForegroundSeriviceで常駐させる
androidDeveloperとgoogleApi様を参照してます。
あと、nyan様のサイトも、いっつも参照しています。ありがとうございます。
以下のサンプルコードは、androidのビルドバージョンはapi26以上です。Manifest gradleの確認
Manifest<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>builed.gradledependencies { ... implementation 'com.google.android.gms:play-services-location:17.0.0'NotificationしないクラッシュCode
Notificationするとコードが長くなるので、まずはシンプルに動作確認するためのコードです。
起動すると位置情報を取得し始め、ボタンプッシュでサービスと位置情報取得を破棄。
5秒経つとクラッシュMainActivitypublic class MainActivity extends AppCompatActivity { static MainActivity activity; static TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); activity = MainActivity.this; textView = findViewById(R.id.textView); Button button = findViewById(R.id.button); final Intent intent = new Intent(this,MyService.class); startForegroundService(intent); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(intent); } }); } }MyServicepublic class MyService extends Service { MainActivity activity; TextView textView; FusedLocationProviderClient fusedLocationClient; LocationCallback myCallback; @Override public void onCreate() { super.onCreate(); activity = MainActivity.activity; textView = MainActivity.textView; fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity); } @Override public int onStartCommand(Intent intent,int flags,int startId){ // 本当ならここでNotificationを設定してstartForeground // でも見辛くなるので今回は省略 myCallback = new myCallback(); // LocationCallback()インスタンス myCheckPermission(); // ActivityCompat.checkSelfPermission() myGetLocation(); // FusedLocationProviderClient.requestLocationUpdates(); return START_STICKY; } // Manifestで設定したpermissonの ACCESS_FINE_LOCATIONってば // ユーザーデンジャラス なので、permissionの許諾が必要! public void myCheckPermission(){ if(ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100); // requestPermissions()で確認した内容は // 本当ならonRequestPermissionsResult()で処理するのですが省略です }else{ return; } } public void myGetLocation(){ // fusedLocationProviderClientの動作を設定 LocationRequest locationRequest = LocationRequest.create(); locationRequest.setInterval(1000*3); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // では!位置情報を取得するよ!取得した情報はCallback()関数で扱います! fusedLocationClient.requestLocationUpdates(locationRequest,myCallback,null); } // MainActivityで、ストップボタンを押すと、Serviceが破棄されるようにしたので // その時に、onDestroyが呼ばれます // onDestroy()でfusedLocationProviderClientを破棄するよ! @Override public void onDestroy() { super.onDestroy(); fusedLocationClient.removeLocationUpdates(myCallback); } @Override public IBinder onBind(Intent intent) { return null; } // LocationCallback()です。 // 取得した位置情報を扱うのはこのクラス! class myCallback extends LocationCallback{ @Override public void onLocationResult(LocationResult locationResult){ super.onLocationResult(locationResult); // locationResultに位置情報があるので、それを使おう! double latitude = locationResult.getLastLocation().getLatitude(); String strLatitude = String.valueOf(latitude); textView.setText(strLatitude); } } }常駐させ、緯度経度高度を取得するCode
Startボタンで位置情報取得と表示を常駐させます。
Stopボタンでサービスと位置情報取得を破棄します。
レッツゴー!MainActivitypublic class MainActivity extends AppCompatActivity { // Serviceから参照するUI部品をstaticに static MainActivity activity; static TextView textAlutitude; static TextView textLatitude; static TextView textLongitude; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // オブジェクトを取得! activity = MainActivity.this; textAlutitude = findViewById(R.id.textAltitude); textLatitude = findViewById(R.id.textLatitude); textLongitude = findViewById(R.id.textLongitude); Button btnStart= findViewById(R.id.btnStart); Button btnStop = findViewById(R.id.btnStop); // StartボタンでForagroundServiceスタート // StopボタンでForegroundServiceストップ // ForegroundServiceストップでMyService.onDestroy()でFusedLocationProviderClientも破棄 final Intent intent = new Intent(activity,MyService.class); btnStart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startForegroundService(intent); } }); btnStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(intent); } }); } }MyServicepublic class MyService extends Service { // オブジェクトをグローバルに MainActivity activity; TextView textAltitude; TextView textLatitude; TextView textLongitude; FusedLocationProviderClient fusedLocationClient; LocationRequest locationRequest; LocationCallback locationCallback; @Override public void onCreate() { super.onCreate(); // FusedLocationProviderClient は onCreate()で生成するみたい // オブジェクトを取得! activity = MainActivity.activity; textAltitude = MainActivity.textAlutitude; textLatitude = MainActivity.textLatitude; textLongitude = MainActivity.textLongitude; fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); // LocationRequestを設定しときます // 5秒ごとに詳細な位置情報を取得するように設定 locationRequest = LocationRequest.create(); locationRequest.setInterval(1000*5); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } public int onStartCommand(Intent intent, int flags, int startId){ // 常駐させたいので通知を出します // 通知コンテンツ、重要度、チャンネルを設定 Notification notification; NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id"); Intent pIntent = new Intent(this,MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this,0,pIntent,0); notification = builder.setSmallIcon(R.drawable.notification_icon) .setContentTitle("NotificationTitle") .setContentText("NotificationText") .setContentIntent(pendingIntent) .build(); int importance = NotificationManager.IMPORTANCE_LOW; NotificationChannel channel = new NotificationChannel("id","name",importance); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); // 5秒以内に startForeground !! 急げ! startForeground(1,notification); // LocationCallback()は、requestLocation,Update,removeで使うので、ここで作成しとく locationCallback = new LocationCallback(){ @Override public void onLocationResult(LocationResult locationResult){ super.onLocationResult(locationResult); String alti = String.valueOf(locationResult.getLastLocation().getAltitude()); String lati = String.valueOf(locationResult.getLastLocation().getLatitude()); String longi = String.valueOf(locationResult.getLastLocation().getLongitude()); textAltitude.setText(alti); textLatitude.setText(lati); textLongitude.setText(longi); } }; checkLocationPermission(); return START_STICKY; } // 位置情報を取得 private void locationUpdate(){ fusedLocationClient.requestLocationUpdates(locationRequest,locationCallback,null); } // permission ACCESS_FINE_LOCATION はユーザーデンジャラスな設定なので許可を確認します public void checkLocationPermission(){ if(ActivityCompat.checkSelfPermission(activity,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ // ACCESS_FINE_LOCATIONの許可がなければダイアログでユーザーに確認 ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100); }else{ locationUpdate(); } } // checkLocationPermission()のrequestPermissionsでユーザに確認した内容を処理します public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults){ if(requestCode == 100){ if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ // 許可が得られたら locationUpdate(); }else{ // 許可が得られなかったら textAltitude.setText("No permission"); } } } // Serviceが破棄されるときに、FusedLocationProviderClientも破棄 @Override public void onDestroy() { super.onDestroy(); fusedLocationClient.removeLocationUpdates(locationCallback); } @Override public IBinder onBind(Intent intent) { return null; } }今回も、かなり時間を掛けました。位置情報を常駐的に取得するのって、僕にはハードル高すぎました。このコードを作るまでに約2週間。行ったり来たりを繰り返して、やっとでした~。
今回も亀の歩みですね。
亀の歩みでも、諦めないでもがき続けると、前進できるんだなって感じたよ。
無理かな無理かなと思っても、前進できるんだね。
まだまだ全然実力不足なんだけれど、面白い。すごく楽しい!