ラベル iOS の投稿を表示しています。 すべての投稿を表示
ラベル iOS の投稿を表示しています。 すべての投稿を表示

2015-12-20

MakeAppIcon -- アイコンとリードのジェネレーター

iOS アプリを作るとき、スクリーンのサイズと分解能ごとにアイコンを用意する必要がある。画像の扱いに長けているわけではないし、そもそも面倒な作業である。

MakeAppIcon というウェブサービスを使った。1024x1024 の画像をアップロードすると、iOS と Android のアプリ用アイコンが生成される。iPad Pro 用のアイコンがなかったけれど、1つくらい手動で作るのは苦にならない。

できあがったアイコンセットは、ウェブでダウンロードするのではなくて、メールで受け取る。

MakeAppIcon 側から見ると、

  • iOS/Android のアプリアイコンが必要で、
  • 自力でアイコンを作るのをだるがり、
  • そのための有料ツールを使わない

という特性を持つ人のメールアドレスを集められるということだ。なるほどなぁ。

2015-12-05

GPS 誤差の距離のずれを、移動平均で減らす

GPS の電波を拾いにくい市街地で測定した経緯度を、地図上にマッピングしていくと、けっこうずれている。


「けっこう」ってどのくらいだよ、っていう話ではあるけれど。ランニングの記録なので、ばっちりの位置が欲しいわけではない。けれど、このくらいずれると、距離にして 3-5%ずれる。1km あたり 7分ペースで走っている場合、距離が 3% ずれると、1km あたり 6分48秒で走っていることになる。

1km あたり12秒の誤差が、42km 積み重なると、8分半になる。地味に気になる。

念の為に書いておくと、マラソンレースにおける距離は、路肩には30cmぐらいまで迫るのを限度として、最短パスで測られるとかだ。なので、多くのランナーは最短コースを走れないので、GPS の測定誤差が完全にゼロであっても、42.195km よりも長めに走ることになる。閑話休題。

GPSの誤差は、高周波成分をなくせばいいんだろうなぁと思った。緯度と経度を、測定ポイントではなくて、移動平均を扱えばよいだろう。

やってみた結果、時間にして5秒、距離にして10m程度で移動平均をとると、距離の誤差が1%くらいになる。ちなみに iPhone 5 。これ以上、平均を算出するポイント数を多くすると、コーナーがなまりすぎる。




2015-12-02

iOS アプリ全体で navigation の見栄えを変更する UINavigationBar.appearance()

iOS の navigation という UI コンポーネントがある。設定を深入りしていく用途なんかに使う。しかも、ストーリーボードで深入りする方向に画面遷移を定義すると、戻っていく方向の遷移は「< Back」ってラベルまでつけて、自動的に実装してくれて便利。

アプリ全体で、この文字色をカスタマイズするには、AppDelegate.swift に以下のようなコードを書く。

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let color = UIColor(red: 113/255.0, green: 61/255.0, blue: 150/255.0, alpha: 1)
        UINavigationBar.appearance().tintColor = color
        UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : color]
        return true
    }
    ...
}

tintColor は左右にある「<Back」とかの色、titleTextAttributes は上部中央のラベルの見栄えを指定する。

各画面でこのへんの文字を outlet として参照し、パラメータを変更しても、画面には反映されない。おそらく一旦描画したあとは、参照しないのだろう。

このへんの文字は UILabel のサブクラスっぽいので、UILabel で入れ替えると、見栄えが反映されるらしい。ただ、自動的に追加される「< Back」はデフォルトのままになってしまう。頑張って参照しようと思えばできるのかも。


じゃあナビゲーションをサブクラスにしようかな、という誘惑を思いとどまり、丁寧にググったら、上記のAppDelegate に書いておく方法が見つかった。 

2015-10-31

バックグラウンドの Location update で、local notification を出す iOS アプリ

移動中に、地理的な条件によって、ユーザーに指示をだす iOS アプリを作ろとうしている。

地理的な位置を管理する CoreLocation サービスは、バックグラウンドでも動き続けるので、これを使うことにした。いろいろ情報があったけれど、集約してひとつのアプリとして動かすのに時間がかかったのでメモしておく。


  • XCode Version 7.1 (7B91b) on OS X El Capitan 10.11.1
  • Xcode で File → New → Project → iOS Application → Single View Application
  • CoreLocation framework をプロジェクトに追加
  • Background の "Location updates" を有効にする
  • info.plist に NSLocationAlwaysUsageDescription キーを追加。値はユーザーに許可を求めるときの文字列。
  • この例では ViewController.swift には触らない。けれど、以下のコードを ViewController クラスに実装しても動く。
  • AppDelegate.swift を以下のように編集する

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
    var window: UIWindow?
    lazy var locationManager: CLLocationManager! = {
        let manager = CLLocationManager()
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.pausesLocationUpdatesAutomatically = false
        manager.allowBackgroundLocationupdates = true
        manager.delegate = self
        manager.requestAlwaysAuthorization()
        return manager
    }()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let settings = UIUserNotificationSettings(forTypes: [.Alert], categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        locationManager.startUpdatingLocation()
        return true
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let cond = true  // 何か条件判定をいれる。常に true だと通知しまくるので注意。
        if cond == true {
            let notification = UILocalNotification()
            notification.alertBody = "Hello"
            UIApplication.sharedApplication().presentLocalNotificationNow(notification)
        }
    }
    // 他のメソッドはそのまま触らない
}

allowBackgroundLocationupdates を true にすることに気づかなくて、長い時間を費やしてしまった。デフォルトの false のとき、アプリが foreground と background のときにはデリゲート関数が呼ばれるけれど、suspend 状態では呼ばれない。なので、最初は通知が出るが、しばらくすると出ない、という現象が起こる(そのように見えた気がする)。

ざっとでもいいから、ドキュメントを読む癖をつけねば。

2015-10-24

iOS の UILocalNotification でユーザーに指示を出す

iOS 9.1/Swift で、定期的に音とバイブを鳴らすコードを書いた。移動中の人間に、スマートフォンから、音声とバイブで〇〇せよという指示を与えられるか、を確認することが目的だ。

NSTimer を使って、定期的に関数を呼び出し、その関数の中で AVAudioPlayer オブジェクトの play() メソッドと、AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) を呼び出すコードを書いた。アプリがフォアグラウンドにあるときは、定期的に音もバイブも鳴るのだけれど、バックグラウンドに入ると音もバイブも鳴らない。

iOS アプリの開発経験のある斧さん(仮名)によると、「用途次第だが、音はともかくバイブを制御できることを期待するな、タイマーもだるいから諦めろ」ということだった。

今回はあくまで実験なので、UILocalNotification をいくつも作って、スケジューリングすることにする。

さて、ポケットにスマートフォンを入れて、移動してみたところ、バイブが鳴ってることは分かるが、仮に振動パターンを作ったとしても、判別できなさそうだ。

一方、ボリュームを大きくしていると、胸ポケットに入れてても、尻ポケットに入れてても、音声による指示は聞こえる。

// Permission
UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Sound, .Alert], categories: nil))

// Setup local notifications
let COUNT = 5
Let INTERVAL = 60

for i in 0 ..< COUNT {
    let notification = UILocalNotification()
    notification.alertBody = alert
    notification.timeZone = NSTimeZone.defaultTimeZone()
    notification.fireDate = NSDate(timeIntervalSinceNow: Double(i+1) * INTERVAL)
    notification.soundName = "foo.m4a"
    UIApplication.sharedApplication().scheduleLocalNotification(notification)

} 

2015-10-17

iPhone アプリ開発をかじろうとする

iPhone/Android アプリのディレクション(仕様策定と、もろもろの意思決定みたいなの)をしたことはあるのだけれど、実際に作ったことはなかった。だいたいが通信やドメインモデル的なデータ構造を主に担当することが多かったわけで。

そんなわけで iPhone アプリの作り方を知ろうと思い立った。

だいたい2日もすると、やる気がなくなってしまうので、勢いで本を購入。簡単すぎるくらい簡単なところから、と思って、簡単そうな本を買ってやってみた。基本的に書いたとおりに写経すればいいんだけど、うっかり、Xcode 7 をインストールしてしまって、微妙に違う箇所があったりする。



この本、構成はいいんだけど、たとえがイマイチなので、好きではない。例示ではなくて、たとえ。

とはいえ、書いてあるとおりに書くと、動く。その後で解説がある、という構成は、私にとって分かりやすい。

続いて、Apple のサイトにある iOS 9、 Xcode 7 のチュートリアルもやってみた。ふむふむ。

Swift は言語仕様的に、冗長なところがあって、同じことをするために複数の書き方があるように見える。class があれば struct は要らないだろとか、継承、extension、プロトコルが地味に被ってるようなとか、delegate は機能じゃなくてデザインパターンかよとか。

けれど、誰かが「言語の問題ではくて、OS X や iOS アプリの既存フレームワークを使うために、そのようなことになってしまっている」と話している見て、納得した。

アプリ開発を請け負えるかと言われると、まったくもって無理ではあるけれど、デバッグの手伝いくらいは(ピザを注文する以外にも)できるようになったような気はする。