青森県のオープンデータを使った「公衆 Wi-Fi スポット」を探せる iOS アプリを作った

青森県のオープンデータは「青い森オープンデータカタログ」にある。

オープンデータで作成されたものはサイト内の「アプリマーケット」というところに登録できるが、みた感じスマホアプリがなく、

アプリマーケット - 青い森オープンデータカタログAoi Mori Open Data Catalog

「活用事例」を見ても個人でスマホアプリ作っている感じがなかったので、今回試しに作ってみた。

活用事例 - 青い森オープンデータカタログAoi Mori Open Data Catalog

アプリの元になったデータはこの「青森県公衆無線LANアクセスポイント一覧」

青森県公衆無線LANアクセスポイント一覧 - 青い森オープンデータカタログAoi Mori Open Data Catalog

データは CSV であるが、実際にはこれをそのままアプリで使うのではなく、アプリで使いやすいように Python で加工して、json ファイルにしたものをアプリで使用。

たとえば、まったく同じ内容の施設が重複していたりするので、それをひとつにしたりとか、ひとつの施設に複数の Wi-Fi スポットがあったりするのでまとめたりとか。。

そんな感じで作りましたよ。

青森県 公衆Wi-Fiマップ

青森県 公衆Wi-Fiマップ

  • Daisuke Tonosaki
  • Navigation
  • Free

あ、、青森県が出身地です。


今回 iOS 15 以降がターゲットのアプリにしたのだけど

iOS 15 だと属性付き文字列を NSAttributedString ではなく新しい AttributedString を使って作れるので、以前より直感的に作れる気がする。

AttributedString

たとえばこんな表示をしたければ、AttributedString はこう作る。

f:id:daisuke-t-jp:20211018210051p:plain

var text1 = AttributedString("これは赤く小さい ")
text1.foregroundColor = .red
text1.font = .systemFont(ofSize: 16)

var text2 = AttributedString("これは青く大きい ")
text2.foregroundColor = .blue
text2.font = .boldSystemFont(ofSize: 20)
        
label.attributedText = NSAttributedString(text1 + text2)

iOS の Google AdMob のテスト広告が出なくなってしまった時の対応

ここに書いてある「デモ広告」のユニット ID を使って、テスト広告を表示させていたのだが、いつの間にか出なくなっていた。

実行時にこんなログが出る。

<Google> Cannot find an ad network adapter with the name(s): com.google.DummyAdapter. Remember to link all required ad network adapters and SDKs, and set -ObjC in the 'Other Linker Flags' setting of your build target.

ドキュメントをよく見たら

注意:アプリで app-ads.txt ファイルを設定している場合は、デモ広告ユニットを使って広告を読み込むために、次の行を app-ads.txt ファイルに含める必要があります。

と記載があったので、 app-ads.txt にコードを追加する。

... 既存の記載 ...
google.com, pub-3940256099942544, DIRECT, f08c47fec0942fa0

そうして数時間経ったら、前のように「デモ広告」が表示されるようになった。 以前はドキュメントにデモ用の app-ads.txt の記載あったかなぁ・・・

ちなみに、↑とは別に「テストデバイス」設定をする方法でも、デモ広告は表示される。

SwiftUI で下から出てくる Picker を作ってみる

UIKit の場合だと UITextField の inputView に UIPicker を設定して、UITextField をタッチすると下からニュッと Picker が出てくる。ができる。

それを SwiftUI でやろうとすると、適当なものが用意されていなかったので、作ってみた。

こんな感じ。

コードは GitHub にあります。

Xcode プロジェクトにローカルの SwiftPackage を追加する

SwiftPackageManager で配布されているパッケージを、ローカルに持ってきてそれを Xcode プロジェクトで参照して使用するメモ。

  1. パッケージのリポジトリを clone する。
  2. 対象のアプリのプロジェクトを開く
  3. Xcode のプロジェクトツリーに、パッケージのフォルダ(Package.swift があるフォルダ)をドラッグ&ドロップする。
  4. ターゲットの Link Binary With Libraries を開く
    • 追加の + ボタンをクリックする。
      • f:id:daisuke-t-jp:20210427214547p:plain:h500
    • 対象の Package を選び、追加する。
      • f:id:daisuke-t-jp:20210427214838p:plain:h500
  5. import できるようになっているので、ビルドする。

ローカルで参照したこの状態では Xcode 上でパッケージのコード編集してビルドすると、変更したパッケージの動作を試せるので、パッケージの挙動を試したり、修正することができる。

写真に写っている人・動物をヒエログリフにする iOS アプリを作ってみた

機械学習フレームワークを使ったアプリを作ってみたくなり、試しに作ってみた。ついでに最近、エジプトのヒエログリフが面白いなあ、と思っていたのでそれをアプリのテーマにした。

Egyptian Hieroglyphs Photo

Egyptian Hieroglyphs Photo

  • Daisuke Tonosaki
  • 写真/ビデオ
  • 無料

Apple の review に提出する際に、かなり機能が単純なアプリだからリジェクトされるかと思ったが、大丈夫だった。
(審査にデモビデオは添付した)

アプリを使って変換すると、こんな感じで写真 → エジプトのヒエログリフの壁画風の画像になる。

f:id:daisuke-t-jp:20210303213230p:plain:w500

f:id:daisuke-t-jp:20210303213422p:plain:h400 f:id:daisuke-t-jp:20210303213440p:plain:h400

アプリの動作はこんな感じ。

www.youtube.com

精度はそんなに良くなく、たとえば写真全体に人や動物が大きく写っていると、残念ながらうまくいかない。。


ざっくりとした処理の流れは↓の感じ。

  1. あらかじめ、使用するヒエログリフの画像を作成して用意しておく
  2. 写真から人や動物を認識する
  3. 認識した領域にもっとも特徴が近いヒエログリフを探し、該当するヒエログリフで写真を置き換える

やってみて悩ましかった点は

多数の画像(ヒエログリフ)から VNFeaturePrintObservation を作ると時間がかかりすぎる。アプリの利用上の障害がある、という問題があった。

解決策としては

  • 実行時に特徴検出を逐次作成するのではなく
  • あらかじめ、各画像の VNFeaturePrintObservation を作成しておいてそれを CoreData で DB に保存しておく
    • そしてそれをアプリにバンドルしておく
  • アプリの実行時には作っておいた DB からVNFeaturePrintObservation を fetch する

という形にした。

VNFeaturePrintObservation の継承元の VNObservationNSSecureCoding を採用しているので、CoreData の Attribute の型を Transformable にして、下のようなカスタムの Transformer クラスを使用することで CoreData に保存できる。

@objc(VNFeaturePrintObservationTransformer)
class VNFeaturePrintObservationTransformer: NSSecureUnarchiveFromDataTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: VNFeaturePrintObservationTransformer.self))
    
    override class var allowedTopLevelClasses: [AnyClass] {
        return super.allowedTopLevelClasses + [VNFeaturePrintObservation.self]
    }
    
    public static func register() {
        let transformer = VNFeaturePrintObservationTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}

Google ML Kit や Core ML はほとんど触ったことがなく難しい印象だったが、やってみると楽しかった。

iOS の Google MLKit で静止画像の ObjectDetection を試してみた

Google MLKit の ObjectDetection での静止画像の解析を試してみた。

公式のサンプルもあるが、バンドルされている静止画像しか解析できない。

そのため、写真を選んで解析する iOS サンプル を作ってみた。

動かすとこんな感じ。

試してみて分かったこと

  • Firebase のセットアップをしなくても使える
    • Google MLKit はもともとは Firebase MLKit という名前だったが
    • Firebase ではなくなり、Firebase のセットアップ(GoogleService-Info.plist の追加など)をしなくても最低限使えるようになったため、とっつきやすい。
  • 認識できるオブジェクトの最大数は 5 である
  • TensorFlowLite と比べると
    • TensorFlowLite ではモデルの用意が必要になるが、Google MLKit ではモデルを用意しなくても、標準でバンドルされているベースモデルを使ってくれるため、とりあえず簡単に解析をしてみたい場合は、Google MLKit を使うと良い。
  • ベースモデル以外にカスタムモデルも使用可能
    • カスタマイズされたモデルを使うことも可能なので、拡張性もある。
    • カスタマイズモデルの取り込み方法は、以下がある。
      • ローカルファイルから読み込む
      • Firebase でホスティングされているモデルを読み込む

CocoaPods で「Your project does not explicitly specify the CocoaPods master specs repo...」の警告が出る

pod のコマンドを実行した時、以下の警告が表示されるようになった。

[!] Your project does not explicitly specify the CocoaPods master specs repo.
Since CDN is now used as the default, you may safely remove it from your repos directory via `pod repo remove master`.
To suppress this warning please add `warn_for_unused_master_specs_repo => false` to your Podfile.

警告メッセージのとおりpod repo remove master をするが

% pod repo remove master
[!] repo master does not exist

master リポジトリがない、と返される。

なので、もうひとつメッセージに書いてある warn_for_unused_master_specs_repo => false を Podfile に追加する。

platform :ios, '14.0'
use_frameworks!

install! 'cocoapods',
            :warn_for_unused_master_specs_repo => false

target 'App' do
# ...
end

これで警告メッセージが出なくなる。

現時点でドキュメントに見当たらなかったが warn_for_unused_master_specs_repoinstall! のオプションに指定するみたい。

https://github.com/CocoaPods/CocoaPods/blob/3593ac03a661fbdd7479a648062a42065d34412c/lib/cocoapods/installer/installation_options.rb#L159


↑の警告と同時に、以下のメッセージが pod コマンド実行時に表示されていた。

Ignoring ffi-1.13.1 because its extensions are not built. Try: gem pristine ffi --version 1.13.1

私の場合 brew で cocoapods をインストールしていたので、試しに

% brew upgrade

をしたら、以後表示されなくなった。