プロトタイピングを通じて分かったAR.jsのメリットとデメリット

AR.jsを使って、新しいインスタレーションのプロトタイピングをやってみたところメリットとデメリットが見えてきたので忘れないうちにまとめておきたい。

“プロトタイピングを通じて分かったAR.jsのメリットとデメリット” の続きを読む

Web AR開発用のJSライブラリ AR.js

これまでARアプリを作るときはARKitを使うことがほとんどだったが、マルチプラットフォームで動くライトウェイトなARアプリを作る機会があり、Web ARを試すことになった。Web ARを実現するためのライブラリは多数存在するが、2024年現在もっとも多く使われているライブラリは調べる限りAR.jsのようだ。サポートしているブラウザの種類や資料の数をみても、今の所AR.jsを使わない理由はなかったのでAR.jsを試してみることにした。

“Web AR開発用のJSライブラリ AR.js” の続きを読む

VSCodeのLive ServerとLocal Port ForwardingでスマホからJSの動作確認する

VSCodeでLive ServerとLocal Port Forwardingを使うと、手軽にVSCodeで編集中のHTML/JSをスマホのブラウザから開いて動作確認できる。

“VSCodeのLive ServerとLocal Port ForwardingでスマホからJSの動作確認する” の続きを読む

Google Slideのスライドをスクリプトで生成する

Google Apps Scriptに用意されているSlidesサービスを使うと、プログラムでスライドを新しく生成することができる。

https://developers.google.com/apps-script/reference/slides/slides-app

SlideAppクラスのcreate メソッドを使うと全く新しいスライドを新規で生成できるが、まっさらなスライドに要素を追加していく処理を全てスクリプトで書くのは結構大変なので、ベースとなるスライドをコピーするアプローチをとった方が何かと楽だ。

// srcFileId: コピー元のスライドのID
// filename: コピーして作られたファイルにつけるファイル名

const copy = DriveApp.getFileById(srcFileId).makeCopy(filename);

// 特定のフォルダに配置したければmoveToを呼び出す
// copy.moveTo(DriveApp.getFolderById(targetFolderId));


const newSlideId = copy.getId();

ファイルのコピーはSlidesサービスではなくDriveサービスのmakeCopyで行う。

const slide = SlidesApp.openById(newSlideId);

コピーしたスライドのIDをSlidesAppのopenByIdの引数に渡す形で、スライドを開き編集していくことができる。

const firstSlide = slide.getSlides()[0]
firstSlide.insertTextBox('Hello');

FlutterアプリのiOS CI/CD設定手順

Bundle Identifierの登録

Certificates, Identifiers & ProfilesでBundle Identifierの登録を行う。

App Store Connectでのアプリの作成

App Store ConnectのApps画面から「New App」を選んでアプリを作成する。Bundle Identifierは↑のステップで作成したものを選ぶ。

Xcode ProjectのBundle Identifier変更

Flutterから書き出されたXcode Projectを開いて、Bundle Identifierを↑のステップで作成したものに変更する。Product Flavorを使っている場合はそれぞれのFlavor用にConfigを作成して、それぞれのBundle Identifierを設定する。

Complianceの設定

Info.plistを開き、App Uses Non-exempt Encryptionの設定を追加する。

Post Cloneスクリプトの追加

Xcode Cloudでプレビルド処理を行うためci_scripts/ci_post_clone.sh を作成する。

パッケージの使用有無によってCocoaPodsの呼び出しの有無、Product Flavor / Dart-define-from-fileの使用有無によって flutter build の呼び出し方/引数が変わるので注意する。

ここまでの設定内容をレポジトリにPushしておく。

Testing Groupの作成

App Store ConnectのアプリのTestFlight設定画面で、Internal Testing用のTesting Groupを作成し、テスト用のApple IDを招待しておく。

Workflowの作成とテスト実行

Xcode CloudのWorkflowの作成を行う。ArchiveアクションのDeployment PreparationはTestFlight (Internal Testing Only)かTestFlight and App Storeのいずれかを選ぶ。Xcode Cloudの仕様なのか不具合なのか、この段階ではTestFlightの配信の設定ができないことがあるので、一旦ここまでで設定を完了し、手動で初回のビルドをトリガーし、ビルドが成功するかを確認する。

Post-Actionの設定とテスト再実行

Workflowの実行に成功したら、WorkflowをEditし、「TestFlight Internal Testing」のPost Actionを追加する。↑で作ったTesting Groupを指定し、再びビルドをトリガーし、ビルドが自動でアップロードされてTestFlightでテスト可能になることを確認する。

FlutterアプリをXcode Cloudでビルドする

数年ぶりにFlutterを試してみたら、思いの外快適で安定している。大規模なアプリでどこまで使えるのかはわからないが、少なくとも趣味で片手間にアプリを書く程度ならかなり良さそうだ。勉強がてら何かしらアプリを一つ作りたいと思い、年末頃から週末の空いた時間に開発を続けているのだが、ようやくそろそろリリースが見えてきた。

“FlutterアプリをXcode Cloudでビルドする” の続きを読む

Google Apps ScriptのBigQuery Serviceのメソッドの引数の調べ方

Google Apps ScriptからBigQueryの機能を利用するにはAdvanced ServiceであるBigQuery Serviceを利用する。

https://developers.google.com/apps-script/reference#advanced_services

このAdvanced Serviceのメソッドを調べるには少し知識が必要になる。

“Google Apps ScriptのBigQuery Serviceのメソッドの引数の調べ方” の続きを読む

Google Apps Scriptでスプレッドシートの内容をオブジェクトの配列として取得する

Apps Scriptでスプレッドシートをテーブル的に使いたい時に、シートの内容をオブジェクトの配列として取得したいケースがよくある。

シート全体のセルの値はgetValues()もしくはgetDisplayValues()メソッドを使って取得することができる。

取得した値のうち、一行目をヘッダー行(keyの配列)として取り出し、残りの行を値として取り出すことで、オブジェクトの配列を作る。

function getRowsAsObjects(sheet) {
  var data = sheet.getDataRange().getDisplayValues();
  
  const header = data.shift();
  
  var rows = data.map(function(row) {
    var dic = {}
    header.forEach((h, idx) => {
      dic[h] = row[idx];
    });
    return dic;
  });

  return rows;
}

すると、このような結果が得られる。

[{name=Apple, date=2024/01/01}, {date=2024-03-13, name=Orange}]

よく書くコードなので、GASのライブラリとしてまとめた。

https://script.google.com/home/projects/1igMdPkdNu4Yg7u_rnBrXYTh7x15KotD0IpikNvrP52fCLV67ClXJ81ut

スクリプトID: 1igMdPkdNu4Yg7u_rnBrXYTh7x15KotD0IpikNvrP52fCLV67ClXJ81ut

使い方

var objects = SheetValues.getRowsAsObjects(SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TestSheet"))

Apps Scriptでスプレッドシートのセルの値を画面に表示された文字列そのままの形で取得したい

Apps ScriptでSpreadsheet Serviceを使うと、Spreadsheet内の任意のセルの値を取得できる。

https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app

処理の内容によって、画面に表示されている内容を文字列としてそのまま取得したい場合と、日付などその文字列が差している内容を適切な型で取得したい場合があるが、Spreadsheetにはそれぞれの目的に合わせて値を取得する関数が用意されている。

getValues

https://developers.google.com/apps-script/reference/spreadsheet/range#getValues()

上のような値が入った状態で、getValues()を使って値を取得すると、下記のような結果が得られる。

values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TestSheet").getDataRange().getValues();

>> [[name, date], [Apple, Mon Jan 01 00:00:00 GMT+09:00 2024], [Orange, Wed Mar 13 00:00:00 GMT+09:00 2024]]

date欄に入力した値は 2024-01-01 という文字列だが、この文字列はSpreadsheet内では自動的に日付として認識されており、getValues()で取得した値は文字列ではなくdate型の値になっている。この挙動は時々厄介だ。ユーザが入力した文字列の値を想定していたら違う値が返ってきていることに気づかず、混乱の原因になったりする。

getDisplayValues

https://developers.google.com/apps-script/reference/spreadsheet/range#getdisplayvalues

getValues()の代わりにgetDisplayValues() を使うと、画面に表示されている内容をそのまま文字列として取得できる。

values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TestSheet").getDataRange().getDisplayValues();

>> [[name, date], [Apple, 2024-01-01], [Orange, 2024-03-13]]

どちらを使うべきか

どちらを使うのが良いかはケースバイケースで判断が難しい。

例えば、date欄で日付を入力してもらうことを想定している場合、上記のようにユーザがもし特定の行の表示フォーマットを変更してしまったとしても、getValues() では表示フォーマットの影響を受けずに日時の値を取得できる。

[[name, date], [Apple, Mon Jan 01 00:00:00 GMT+09:00 2024], [Orange, Wed Mar 13 00:00:00 GMT+09:00 2024]]

一方で、getDisplayValues()では、画面に表示されている内容がそのまま返されるため、これを日時として処理したい場合はどちらのフォーマットで入力されても対応できるように実装する必要が出てくる。

[[name, date], [Apple, 2024/01/01], [Orange, 2024-03-13]]

従って一概にどちらを使うべきとは言えず、ユーザにどのような形式での入力をしてもらうか、運用と合わせて実装方法を考えるしかなさそうだ。