Android, iOSのジオフェンシング機能を調べた

メモ

AndroidiOSも、同時に登録できるジオフェンス数は多くない(Android: 100件、iOS: 20件)。多数のジオフェンスを登録したい場合は工夫が必要。

  • ユーザーの進路に合わせて遠ざかったポイントを削除、近づいたポイントを追加
  • ジオフェンススポットをクラスタリングし、大きい範囲にしておく。大きい範囲に入ったらより詳細なジオフェンスを登録しなおす。

ジオフェンシングとは

特定の領域(ジオフェンス)を定め、領域の境界線を横切ったことを検出することで、領域への「進入」「退出」を検知し、何らかの処理を行うことができる。

ジオフェンスの定め方はいろいろある。

  • 地理的位置を中心とした半径50mの円の範囲
  • Wi-Fi アクセスポイントの電波を検知できる範囲
  • Bluetoothビーコンの電波を検知できる範囲

Android

Google Play services location APIs の機能として提供されている。

Create and monitor geofences

仕様

  • 同時に設定できるアクティブなジオフェンスは、1アプリにつき100件まで
    • バイスをマルチユーザーで利用している場合は、1アプリにつきユーザーごとに100件まで
  • ジオフェンス内滞留時間を指定することができる
    • 指定の時間滞在していたら通知する、といった調整が可能
  • ジオフェンスの有効期限を設定することができ、期限切れになると自動的に削除される

iOS

CoreLocationフレームワークに、地理的領域の観測機能とビーコンによる領域観測機能が用意されている。今回は、地理的領域の観測機能についてのみ調査した。

https://developer.apple.com/jp/documentation/UserExperience/Conceptual/LocationAwarenessPG/RegionMonitoring/RegionMonitoring.html

仕様

  • 同時に設定(監視)できる地理的領域は、1アプリにつき最大20件
  • アプリケーションが実行していない時でも監視されており、実行されていないときに領域の境界線を横切った場合はアプリケーションがバックグラウンドで起動される。
  • 「設定」アプリで、ユーザーが「位置情報サービス」を無効にしている場合は利用できない。
  • 「設定」アプリで、ユーザーが「Background App Refresh」をデバイスかアプリケーションのどちらかで無効にしている場合は利用できない。
  • バイス機内モードになっていて、必要なハードウェアの電源を入れられない場合は利用できない。

iOS11でnavigationItem.titleViewにセットしたViewの表示位置がずれる

guard let width = navigationController?.navigationBar.frame.size.width,
    let height = navigationController?.navigationBar.frame.size.height else {
    return
}

// NavigationBarのほぼ幅いっぱいに表示する(ただし少し余白はできる)
let rect = CGRect(x: 0, y: 0, width: width, height: height)

let titleView = MyTitleView(frame: rect)
navigationItem.titleView = titleView

NavigationBarの中にViewをセットしていたところで、iOS11ではずれて表示された。

uinavigationcontroller - iOS 11 navigationItem.titleView Width Not Set - Stack Overflow

上記回答にあるように、
View側で intrinsicContentSize を以下のようにオーバーライドすることで、ずれないで表示できた。

override var intrinsicContentSize: CGSize {
    return UILayoutFittingExpandedSize
}

Stringの末尾の改行コードを削除したい

String#replace()でやろうとしたけれど、改行コード3つ(\r, \n, \r\n)を書くのやだなーと思い調べた。 そうしたら、trim()で削除される文字に改行コードもふくまれることを知った。

String (Java Platform SE 8)

trim()の説明では、「空白」とは文字コードが'\u0020'より小さい文字のことを指しているとのこと。 改行コードの文字コードは'\u0020'より小さい。

Unicode一覧 0000-0FFF - Wikipedia

trim()すると、改行コード以外の制御文字も削除されるけれど、今回は問題ない。

warning: Auto Layout Localization: Fixed leading and trailing constraints with a center constraint may cause clipping.

Xcode9.1で、storyboardでこんな警告がでた。

warning: Auto Layout Localization: Fixed leading and trailing constraints with a center constraint may cause clipping.

「センター揃えの制約と一緒に、固定のleading/trailingの制約をつけると見切れちゃうかもよ」ということ? adjustsFontSizeToFitWidth を 有効にしているけどだめなのだろうか。

ここの回答の通りに、ローカライズされていたStoryboardを一旦参照解除して再度追加したら、警告がでなくなった。

ios - Xcode 9 - Localization Issue Warning Storyboard - Stack Overflow

深追いはしない。
ローカライズはコードからやることにする。

Realm Objective-CをSwiftから使うときに、NSNumber?なプロパティの初期値をnilにできない

RLMObjectを継承したモデルクラスでNSNumber?のプロパティを用意し、「値:なし」を表現したいので、初期値はnilとしました。
Objective-Cからも使いたいので、Int?にはできない)

public class MyData: RLMObject {
    @objc dynamic var myValue: NSNumber? = nil
}

実行すると、以下のエラーで止まる
訳(適当):NSNumberは初期値なしでは保持できません。Swift-nativeな型を使うか、初期値を入れてください。

*** Terminating app due to uncaught exception 'RLMException', reason: 'Can't persist NSNumber without default value: use a Swift-native number type or provide a default value.'

Realm Objective-Cでは、Swift側でNSNumberの初期値をnilにすることはできないみたいです。
また、今後変更もされない様子。

とりあえず NSNumber? -> String? にして対応。

public class MyData: RLMObject {
    @objc dynamic var myValue: String?
}

そもそも、OptionalなNSNumberって、Objective-C側から見えないかもしれない(未確認)。
きっともっと良い解決策はあるはず。

フォーム作成ライブラリのEurekaで、セクションのヘッダーとフッターを表示しない

iOSでのフォーム作成ライブラリのEureka、とても便利に使っています。 github.com

普通に Section を追加すると上下にスペースができるのですが、以下のように設定すると、ヘッダーとフッターのスペースをなくせます。

form +++
    Section() {
        // ヘッダー/フッターを表示しない
        $0.header = HeaderFooterView<UIView>(HeaderFooterProvider.class)
        $0.header?.height = { CGFloat.leastNormalMagnitude }
        $0.footer = HeaderFooterView<UIView>(HeaderFooterProvider.class)
        $0.footer?.height = { CGFloat.leastNormalMagnitude }
    }

調べたら、これはiOS標準の UITableView (Group style) でよく使うようです。
知りませんでした。
Grouped UITableView のセクションヘッダーおよびフッターの余白をなくす方法 - Qiita

Android 8で、クイック設定タイルに開発者向けオプションの「レイアウト境界を表示」を置けるようになった

f:id:myamamic:20180124185053p:plain:w200f:id:myamamic:20180124185107p:plain:w200

設定 -> 開発者向けオプション -> クイック設定開発者用タイル -> レイアウト境界を表示 を有効にすると、クイック設定タイルの編集画面に項目があらわれて、配置できるようになる。

ほかに、

  • GPSレンダリングのプロフィール作成
  • RTLレイアウトの方向を矯正する
  • ウィンドウアニメスケール

のショートカットを、クイック設定タイルに置けます。
もしかしたら Android 7 くらいからあったのかもしれない。
あと、機種によっては無効化されていてできないかもしれない。

便利!