LoginSignup
3
4

More than 5 years have passed since last update.

Google Maps Elevation APIを使って海抜計測アプリを作成してみた

Posted at

私にとって初のiOSアプリをリリースしたので、App Storeに公開するまでの軌跡を残しておく。

:bulb: 作ったもの

いつでもどこでも世界中の海抜を測れるアプリ『KAIVAP
AppIcon_180.png
Simulator-Screen-Shot---iPhone-8---2018-02-12-at-12.23.28.png

:hammer: 使ったもの

:pushpin: 構築手順

きっかけ

何十本とアプリをリリースしているエンジニアの方にお会いし刺激を受けた。
取り敢えず何でもいいから0→1でアプリをリリースしようと思い、歩いているときに「ここは海抜〇〇mです」と書かれた電柱を見てGoogleMapから海抜(標高)を計測できるアプリを作ろうと決める!

アプリ作成

主要部分はこんな感じ。
100行ぐらいしか書いてないですね笑

ViewController.swift
import Foundation
import UIKit
import APIKit
import GoogleMaps
import GooglePlaces

class ViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {

    var locationManager: CLLocationManager!
    var placesClient: GMSPlacesClient!
    var currentLocation: CLLocationCoordinate2D?
    var currentCameraPosition: GMSCameraPosition?
    var zoomLevel: Float = 15.0
    var mapView: GMSMapView!

    // 一部省略

    @IBOutlet weak var elevationLabel: UILabel!
    @IBOutlet weak var calculateButton: UIButton!
    @IBOutlet weak var resetButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
    }

    func setupView() {
        let camera = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 1.0)
        let footerViewHeight: CGFloat = 88.0
        let mapViewSize = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height-footerViewHeight)
        mapView = GMSMapView.map(withFrame: mapViewSize, camera: camera)
        mapView.isMyLocationEnabled = true
        do {
            mapView.mapStyle = try GMSMapStyle(jsonString: mapStyle)
        } catch {
            NSLog("One or more of the map styles failed to load. \(error)")
        }
        mapView.delegate = self

        let marker = GMSMarker()
        marker.position = CLLocationCoordinate2D(latitude: -33.86, longitude: 151.20)
        marker.title = "Sydney"
        marker.snippet = "Australia"
        marker.map = mapView
        view.addSubview(mapView)
        view.sendSubview(toBack: mapView)

        locationManager = CLLocationManager()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.distanceFilter = 50
        locationManager.startUpdatingLocation()
        locationManager.delegate = self

        placesClient = GMSPlacesClient.shared()
    }

    func calculateElevation(lat: Double, lng: Double) {
        let request = GetElevationRequest(lat: lat, lng: lng)
        Session.send(request) { [weak self] result in
            guard let `self` = self else { return }

            switch result {
            case .success(let elevation):
                if let elevation = elevation.results.first?.elevation {
                    if elevation == 0 {
                        self.elevationLabel.textColor = UIColor.init(hex: "CB1B45")
                        self.elevationLabel.text = "0(計測不能)"
                    } else {
                        if elevation > 5 {
                            self.elevationLabel.textColor = UIColor.init(hex: "333333")
                        } else {
                            self.elevationLabel.textColor = UIColor.init(hex: "DB4D6D")
                        }
                        let text = NSString(format: "%.1f", elevation)
                        self.elevationLabel.text = text as String
                    }
                }
            case .failure(let error):
                print("error: \(error)")
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            currentLocation = location.coordinate
            let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
                                                  longitude: location.coordinate.longitude,
                                                  zoom: zoomLevel)

            if mapView.isHidden {
                mapView.isHidden = false
                mapView.animate(to: camera)
            } else {
                mapView.animate(to: camera)
                calculateElevation(lat: location.coordinate.latitude, lng: location.coordinate.longitude)
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .restricted:
            print("Location access was restricted.")
        case .denied:
            print("User denied access to location.")
            mapView.isHidden = false
        case .notDetermined:
            print("Location status not determined.")
        case .authorizedAlways: fallthrough
        case .authorizedWhenInUse:
            print("Location status is OK.")
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        locationManager.stopUpdatingLocation()
        print("Error: \(error)")
    }

    func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
        currentCameraPosition = position
    }

    @IBAction func didPressCalculateButton(_ sender: Any) {

        if let currentCameraPosition = currentCameraPosition {
            calculateElevation(lat: currentCameraPosition.target.latitude, lng: currentCameraPosition.target.longitude)
        }
    }

    @IBAction func didPressResetButton(_ sender: Any) {

        if let currentLocation = currentLocation {
            self.mapView.animate(toLocation: currentLocation)
            self.self.calculateElevation(lat: currentLocation.latitude, lng: currentLocation.longitude)
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

実機ビルドが出来ない!?

アプリが完成したので実機で現在地が取れているか確認しようと思い、実機ビルドに挑戦した。
が、シミュレータでは発生しなかったエラーが出現!?!?

Command /bin/sh failed with exit code 1

数日間ハマっていたが、下のダイアログを Xcodeインストール時に拒否していたことが原因だと判明!
Xcodeを再インストールし、パスワードを入力して「常に許可」を選択したらエラーが消えてくれました>_<

access_xcode.png
Xcodeの「キーチェーンログインのパスワードを入力してください」パスワードが通らない

エラー祭り!?!?

やっと実機ビルドが出来る!!!と思ったら新たなエラーが。。。
今度は何やねん(ーー;)

dyld: Library not loaded: @rpath/Pods_xxx.framework/Pods_xxx

あー。ライブラリーが読み込めていないのかー。意味の分かるエラーで助かるわー。
と思いきや!?!?
そんな優しいエラーではなかった。

Library not loaded エラー?ここを見直そう
Carthageを使ってライブラリを管理する

色々な対処法を試してみたが、、、エラーは一向に消えてくれない。
そこでふと思ったのが、
実機ビルド時のみ起こるってことは証明書周りでミスってる??

確認してみると…
CertificatesProvisioning Profilesには何も問題がないんですよ。
キーチェーンアクセスを見ても有効期限も切れてないし。

数日後…やっと解決策を見つけることが出来ました!
証明書を「常に信頼」から「システムデフォルトを使用」に変更!

qiita_01.png

dyld: Library not loaded: @rpath/libswiftCore.dylib

どこかのタイミングで変えてしまったんでしょうね。
デフォルトは「システムデフォルトを使用」になっています。

エラー地獄から抜け、やっとの思いで実機ビルドに成功しました!

Archive後のValidateで躓く

iTunes Store Operation Failed
ERROR ITMS-90087: "Unsupported Architectures. The executable for ${APP_NAME}.app/Frameworks/APIKit.framework contains unsupported architectures '[x86_64, i386]'."

スクリーンショット 2018-02-10 8.15.41.png

Check and Remove Unsupported Architecture [x86_64, i386] in IPA / Archive

上の記事を参考に、サポートされていないアーキテクチャーを外したら上手くいきました!

アプリ公開

アプリを申請してからは比較的順調にリリースまで辿り着けました。
今回一番お世話になった記事を載せておきます。
↓↓↓
iOSアプリを登録、申請して公開するまで

まとめ

プロジェクトを立ち上げてからリリースするまで、
コードを書いている時間 >>> Xcodeの設定に悩まされる時間 だった気がします笑
ですが、

  • アプリ申請の流れを把握できた
  • Xcodeの設定を見直すことが出来た(次回からは困らない!はず)
  • iOSアプリ開発者の仲間入りが出来た
  • 証明書周りの知識がほんの少しだけついた

など得るものは大きかったです!

アプリリリースはそんなに難しくない!!!
これからもバンバンiOSアプリをリリースしていきたいと思います!

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4