JS Bundleの中身を見たい

ReactNativeアプリを実行する時、JSコードは Metoro によって JS Bundle という1つのファイルにバンドルされる。

そのバンドルの中身はローカルでMetoroが起動している状態の時に

http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false

で確認することができる。

ファイルはデバイスのメモリに置かれているので、プロジェクトファイルに作成されることはない。

What is metro bundler in react-native? - Stack Overflow

JS あるキーが重複したオブジェクトを取り除く

const a = [
  {
    name: 'Risa',
    age: 22,
  },
  {
    name: 'Ryu',
    age: 20,
  },
  {
    name: 'Risa',
    age: 22,
  },
];

このような配列がある。要素のオブジェクトの name の値が重複しているオブジェクトを1つ取り除きたい。

const mapped = new Map(a.map((_a) => [_a.name, _a]));

Mapインスタンスを作成。a.map((_a) => [_a.name, _a]) で name をキー、_aそのものを値として作成。

この時点で重複が取り除かれる。

// 作成されたMapインスタンス
{'Risa' => {…}, 'Ryu' => {…}}

次にこのインスタンスからイテレーターオブジェクトを作成する。要素が列挙される。

Map.prototype.values() - JavaScript | MDN

const iterator = mapped.values();

Array.fromでイテラブルなオブジェクトを配列に変更する。

Array.from() - JavaScript | MDN

const newArray = Array.from(iterator)

// [{name: 'Risa', age: 22}, {name: 'Ryu', age: 20}]

react-native-mmkvを導入したら Undefined symbols for architecture x86_64 が出た

react-native0.68.4

どうやら react-native-firebase を導入した時にPodfileに加えた use_frameworks! が原因っぽい。

結論としては、react-native-mmkvを静的ライブラリとして読み込んであげると解決した。

pre_install do |installer|
  installer.pod_targets.each do |pod|
    if pod.name.eql?('react-native-mmkv')
      def pod.build_type;
        Pod::BuildType.static_library
      end
    end
  end
end

pre_installはpodをインストールする前に何らかの変更を加えてくれる。

BuildType.static_libraryにより静的ライブラリとして登録。

github.com

www.rubydoc.info

www.rubydoc.info

Swiftでマップや位置情報を使う

Swift初心者のメモです。

iOS15で検証

マップ

基本となるインスタンス

import MapKit

let mapView = MKMapView()

ユーザーの現在地表示(青ポチのあれ)

mapView.showsUserLocation = true

ラッキングモード(青ポチが自動で移動するあれ)

mapView.userTrackingMode = MKUserTrackingMode.follow

// 方向を表示する場合
// mapView.userTrackingMode = MKUserTrackingMode.followWithHeading

MKUserTrackingMode.followまたは .followWithHeading を指定していると、初回表示で縮尺や中心を指定してなくても現在地が中心になる。

中心となる緯度経度の設定

let lat = CLLocationDegrees(<緯度>)
let lng = CLLocationDegrees(<経度>)
let loc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng)
mapView.setCenter(loc, animated: true)

縮尺の設定

var region: MKCoordinateRegion = mapView.region
region.span.latitudeDelta = 0.1
region.span.longitudeDelta = 0.1
region.center = loc // locは上記で定義
mapView.setRegion(region, animated: true)

setRegionを使う場合には region.center で中心地も指定できるので setCenter を使用する必要はない

タップした位置の緯度経度を取得する

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))

mapView.addGestureRecognizer(tapGesture)

...

@objc func mapTapped(_ sender: UITapGestureRecognizer) {
  if sender.state == .ended {
    let tapPoint = sender.location(in: mapView)
    let coordinate = mapView.convert(tapPoint, toCoordinateFrom: mapView)
    print(coordinate.latitude)
    print(coordinate.longitude)
   }
}

アノテーションを加える(ピンみたいなマークのあれ)

let annotation = MKPointAnnotation()

annotation.coordinate = coordinate // CLLocationCoordinate2D

mapView.addAnnotation(annotation)

緯度経度から住所などの追加情報を取得

逆ジオコーディングと言われるやつ。

let cla = coordinate.latitude // CLLocationCoordinate2D
let clo = coordinate.longitude // CLLocationCoordinate2D

let location = CLLocation(latitude: cla, longitude: clo)

CLGeocoder().reverseGeocodeLocation(location, completionHandler: { placemarks, error in
  if error != nil {
    return
  }

  let placemark = placemarks.first
})

位置情報

基本となるインスタンス

import CoreLocation

let locationManager = CLLocationManager()

受け取りたい位置情報の正確さ

locationManager.desiredAccuracy = kCLLocationAccuracyBest // 最も精度が高い

iOSアプリの場合は kCLLocationAccuracyBest がデフォルト

バイスで位置情報が使用可能かどうか

CLLocationManager.locationServicesEnabled()

これはアプリレベルで位置情報の使用が許可されているかどうかではなく、デバイスレベルで使用可能かどうか。

設定の プライバシー > 位置情報サービス がオフになっているとfalseが返る。

使用許可のステータス

let status = locationManager.authorizationStatus

位置情報使用のリクエス

// バックグラウンドでも許可使用したい場合
locationManager.requestAlwaysAuthorization()

// アプリ使用中の許可を取りたい場合
locationManager.requestWhenInUseAuthorization()

どちらを実行しても「アプリ使用中の位置情報の取得の許可」のためのダイアログが表示される。

文言も NSLocationWhenInUseUsageDescription で指定したものが表示される。

このメソッドを実行した時点で CLLocationManager.locationServicesEnabled() がfalseだった場合、「位置情報サービスをオンにしてください」というアラートが自動で表示される。

requestAlwaysAuthorization()を実行した場合

初回ダイアログ

「Appの使用中は許可」を押すとコード上のステータスは authorizedAlways になる。

「一度だけ許可」を押すとコード上のステータスは authorizedWhenInUse になる。

「許可しない」だと denied になる。

authorizedWhenInUse の場合はバックグラウンドでは位置情報が更新できない。なのでバックグラウンドでも位置情報の更新を取得する必要があるアプリはアラートなので設定を authorizedAlways にするように誘導する必要がありそう。

This authorization allows you to use all location services and receive location events only when your app is in use. To continue using location services in the background, enable Continuous Background Location Updates and start the services while the app is in use.

denied の場合は位置情報が使用できないので、必須のアプリではアラートを出すなどしてアプリの機能を使えないことの通知が必要になりそう。

Appの使用中は許可を選択した場合

アプリの設定画面では「このAppの使用中のみ許可」になる。

コード状は authorizedAlways なので位置情報はバックグラウンドでも更新される。

しばらくして表示されるダイアログの 「”常に許可”に変更 」を押した時点でアプリ側の設定も変わる。

ここで「”使用中のみ許可”のままにする」にすると authorizedWhenInUse になる。

位置情報の許可ステータス変更によって実行されるdelegate

func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
  let status = locationManager.authorizationStatus
  switch status {

  }
}

位置情報の変更を検知させる

// 位置情報の更新を検知した場合、locationManagerを実行させる
locationManager.startUpdatingLocation()

...

// .startUpdatingLocation()が呼ばれている場合、位置情報の更新を受け取り実行される
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

}

terraformからIAMを作成する時に Error retrieving IAM policy for project ~ googleapi: Error 403: The caller does not have permission

terraformからIAMを作成するために以下のようなコードを書いた。

resource "google_service_account" "scheduler_invoker" {
  display_name = "Schedler Invoker"
  account_id   = "scheduler-invoker"
}

resource "google_project_iam_member" "run_invoker" {
  role = "roles/run.invoker"
  member = "serviceAccount:${google_service_account.scraping_scheduler_invoker.email}"
  project = var.project
}

これで apply すると以下のようなエラーが出た。

Request `Create IAM Members roles/run.invoker serviceAccount:~"` returned error: Error retrieving IAM policy for project "~": googleapi: Error 403: The caller does not have permission, forbidden

IAMポリシーをいじるためのロールが terraform の credentials に渡したIAMに存在しない。

IAMに「Project IAM 管理者」を付与すると解決する。