20201114のiOSに関する記事は5件です。

【備忘録】iOS 14 細かいTips 写真アクセス権限・バックボタン

iOS 14のTipsを書いていこうと思います。

写真のアクセス権限の変更

iOS 13までは写真のアクセス権限の選択肢が許可しないOKの2択でしたが、
iOS 14からは写真のアクセス権限の選択肢が 写真を選択全ての写真へのアクセスを許可許可しないの3択になりました。
iOS 14では写真個別にアクセス権限を与えれるようになりました。

iOS 13ダイアログ
Screen Shot 2020-11-14 at 2.11.14.png

iOS 14ダイアログ

Screen Shot 2020-11-14 at 2.14.44.png

写真のアクセス権限の呼び出しは以下のコードでOSに合わせてダイアログを表示します。

PHPhotoLibrary.requestAuthorization { _ in
   // 省略
}

iOS 14でも従来のダイアログを出すには?

アプリで写真を保存するだけの用途なら従来のダイアログで問題ないと思います。

まず、Info.plistにPrivacy - Photo Library Additions Usage Description (NSPhotoLibraryAddUsageDescription)を設定して文言を追加します。

スクリーンショット 2020-11-14 2.38.57.png

なら以下のコードで大丈夫です。

if #available(iOS 14, *) {
     PHPhotoLibrary.requestAuthorization(for: .addOnly) { _ in
        // 省略     
     }
} else {
     PHPhotoLibrary.requestAuthorization { _ in
        // 省略        
     }
}

requestAuthorizationというメソッドで 写真のみ追加もしくは 読み出し/書き込みのどちらかで指定して呼び出しできるので .addOnlyを指定すると従来のダイアログが出すことができます。

Screen Shot 2020-11-14 at 2.40.21.png

バックボタン

iOS 14からバックボタンを長押しすることで前の画面らをリストしたポップアップが表示され、一気に一番最初の画面に戻るなどできるようになりました。

例 設定アプリ
Screen Shot 2020-11-14 at 15.09.03.png

他にもバックボタンの見た目も制御できるようになり、UINavigationItemクラスに以下のプロパティが追加されました。

var backButtonDisplayMode: UINavigationItem.BackButtonDisplayMode { get set }

見た目は3種類設定できます

.default

前の画面タイトルがバックボタンに反映します
※タイトルが入ってなければ Backになります

Screen Shot 2020-11-14 at 15.26.00.png

.generic

バックボタンがBackになります
Screen Shot 2020-11-14 at 15.29.55.png

.minimal

バックボタンに名称が表示されず<だけになります
Screen Shot 2020-11-14 at 15.30.56.png

コード例

if #available(iOS 14.0, *) {
    self.navigationItem.backButtonDisplayMode = .minimal
}

注意

バックボタンの見た目は制御できますが、長押しした際のリストは画面タイトル(self.title)もしくはバックボタン(backButtonTitle)の文言が表示されます。

もし何も文言を入れてないと空欄にまたは同じ文言を入れると、どこの画面に戻るかぱっと見でわからなくなってしまいます。

例 同じ文言
Screen Shot 2020-11-14 at 15.37.57.png

iOS 14のバックボタンの対応として長押しした際にどこの画面に戻るか分かる文言を設定してあげるといいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUI 他のフレームワークを組み合わせると使えるView

SwiftUIの他に各種フレームワークをimportすると使えるViewやModifierです。

MapKit

Mapが使えます。

サンプルコード

import SwiftUI
import MapKit

struct SwiftUIView: View {
    @State var region: MKCoordinateRegion
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        let initialCoordinate = CLLocationCoordinate2DMake(40,40)
        let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
        let region = MKCoordinateRegion(center: initialCoordinate, span: span)

        return SwiftUIView(region: region)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.34.52.png

SpriteKit

SpriteViewが使えます。
GameSceneファイルはXcodeプロジェクトをMultiplatformで作成した際のものを使っています。

サンプルコード

import SwiftUI
import SpriteKit

struct SwiftUIView: View {
    let scene: SKScene
    var body: some View {
        SpriteView(scene: scene)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        guard let scene = SKScene(fileNamed: "GameScene") as? GameScene else {
            abort()
        }
        scene.scaleMode = .aspectFit

        return SwiftUIView(scene: scene)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.36.21.png

AuthenticationServices

SignInWithAppleButtonが使えます。

サンプルコード

import SwiftUI
import AuthenticationServices

struct SwiftUIView: View {
    var body: some View {
        SignInWithAppleButton(.continue) { _ in

        } onCompletion: { _ in

        }
        .frame(width: 300.0, height: 44.0)
        .signInWithAppleButtonStyle(.black)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.54.47.png

StoreKit

appStoreOverlayが使えます。

サンプルコード

import SwiftUI
import StoreKit

struct SwiftUIView: View {
    @State var showOverlay:Bool = false
    var body: some View {
        Button("App Store Overlay") {
            self.showOverlay.toggle()
        }
        .appStoreOverlay(isPresented: $showOverlay) {
            SKOverlay.AppConfiguration(appIdentifier: "687721425", position: .bottom)
        }
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        return SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.46.41.png

AVKit

VideoPlayerが使えます。
ドキュメントには A view that displays the video content from a player object along with system-supplied playback controls. とあるんですが、tvOSだとコントロールが出ない感じです。

サンプルコード

import SwiftUI
import AVKit

struct SwiftUIView: View {
    let player: AVPlayer?
    var body: some View {
        VideoPlayer(player: player)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        return SwiftUIView(player: AVPlayer(url: URL(string: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!))
    }
}

プレビュー

スクリーンショット 2020-11-14 11.34.07.png

SceneKit

SceneView が使えます。scnファイルは各自用意してください。

サンプルコード

import SwiftUI
import SceneKit

struct SwiftUIView: View {
    let scene: SCNScene?
    var body: some View {
        SceneView(scene: scene)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        let scene = SCNScene(named: "Scene.scn")

        return SwiftUIView(scene: scene)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.32.49.png

HomeKit

CameraViewが使えます。
HMCameraSource が必要になりますが、おそらくSwiftUIプレビューでは用意できないので、各自実機でご確認ください。

サンプルコード

import SwiftUI
import HomeKit

struct SwiftUIView: View {
    let cameraSource:HMCameraSource
    var body: some View {
        CameraView(source: cameraSource)
    }
}

画像

IMG_1F757207E2D1-1.jpeg

WatchKit

NowPlayingViewが使えます。

サンプルコード

import SwiftUI
import WatchKit

struct SwiftUIView: View {
    var body: some View {
        NowPlayingView()
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.39.10.png

まとめ

つかおう!HomeKit!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUIを他のフレームワークと組み合わせる

SwiftUIの他に各種フレームワークをimportすると使えるViewやModifierです。

MapKit

Mapが使えます。

サンプルコード

import SwiftUI
import MapKit

struct SwiftUIView: View {
    @State var region: MKCoordinateRegion
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        let initialCoordinate = CLLocationCoordinate2DMake(40,40)
        let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
        let region = MKCoordinateRegion(center: initialCoordinate, span: span)

        return SwiftUIView(region: region)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.34.52.png

SpriteKit

SpriteViewが使えます。
GameSceneファイルはXcodeプロジェクトをMultiplatformで作成した際のものを使っています。

サンプルコード

import SwiftUI
import SpriteKit

struct SwiftUIView: View {
    let scene: SKScene
    var body: some View {
        SpriteView(scene: scene)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        guard let scene = SKScene(fileNamed: "GameScene") as? GameScene else {
            abort()
        }
        scene.scaleMode = .aspectFit

        return SwiftUIView(scene: scene)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.36.21.png

AuthenticationServices

SignInWithAppleButtonが使えます。

サンプルコード

import SwiftUI
import AuthenticationServices

struct SwiftUIView: View {
    var body: some View {
        SignInWithAppleButton(.continue) { _ in

        } onCompletion: { _ in

        }
        .frame(width: 300.0, height: 44.0)
        .signInWithAppleButtonStyle(.black)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.54.47.png

StoreKit

appStoreOverlayが使えます。

サンプルコード

import SwiftUI
import StoreKit

struct SwiftUIView: View {
    @State var showOverlay:Bool = false
    var body: some View {
        Button("App Store Overlay") {
            self.showOverlay.toggle()
        }
        .appStoreOverlay(isPresented: $showOverlay) {
            SKOverlay.AppConfiguration(appIdentifier: "687721425", position: .bottom)
        }
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        return SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.46.41.png

AVKit

VideoPlayerが使えます。
ドキュメントには A view that displays the video content from a player object along with system-supplied playback controls. とあるんですが、tvOSだとコントロールが出ない感じです。

サンプルコード

import SwiftUI
import AVKit

struct SwiftUIView: View {
    let player: AVPlayer?
    var body: some View {
        VideoPlayer(player: player)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        return SwiftUIView(player: AVPlayer(url: URL(string: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!))
    }
}

プレビュー

スクリーンショット 2020-11-14 11.34.07.png

SceneKit

SceneView が使えます。scnファイルは各自用意してください。

サンプルコード

import SwiftUI
import SceneKit

struct SwiftUIView: View {
    let scene: SCNScene?
    var body: some View {
        SceneView(scene: scene)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        let scene = SCNScene(named: "Scene.scn")

        return SwiftUIView(scene: scene)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.32.49.png

HomeKit

CameraViewが使えます。
HMCameraSource が必要になりますが、おそらくSwiftUIプレビューでは用意できないので、各自実機でご確認ください。

サンプルコード

import SwiftUI
import HomeKit

struct SwiftUIView: View {
    let cameraSource:HMCameraSource
    var body: some View {
        CameraView(source: cameraSource)
    }
}

画像

IMG_1F757207E2D1-1.jpeg

WatchKit

NowPlayingViewが使えます。

サンプルコード

import SwiftUI
import WatchKit

struct SwiftUIView: View {
    var body: some View {
        NowPlayingView()
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.39.10.png

まとめ

つかおう!HomeKit!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUIを他のフレームワークと組み合わせると使えるView

SwiftUIの他に各種フレームワークをimportすると使えるViewやModifierです。

MapKit

Mapが使えます。

サンプルコード

import SwiftUI
import MapKit

struct SwiftUIView: View {
    @State var region: MKCoordinateRegion
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        let initialCoordinate = CLLocationCoordinate2DMake(40,40)
        let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
        let region = MKCoordinateRegion(center: initialCoordinate, span: span)

        return SwiftUIView(region: region)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.34.52.png

SpriteKit

SpriteViewが使えます。
GameSceneファイルはXcodeプロジェクトをMultiplatformで作成した際のものを使っています。

サンプルコード

import SwiftUI
import SpriteKit

struct SwiftUIView: View {
    let scene: SKScene
    var body: some View {
        SpriteView(scene: scene)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        guard let scene = SKScene(fileNamed: "GameScene") as? GameScene else {
            abort()
        }
        scene.scaleMode = .aspectFit

        return SwiftUIView(scene: scene)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.36.21.png

AuthenticationServices

SignInWithAppleButtonが使えます。

サンプルコード

import SwiftUI
import AuthenticationServices

struct SwiftUIView: View {
    var body: some View {
        SignInWithAppleButton(.continue) { _ in

        } onCompletion: { _ in

        }
        .frame(width: 300.0, height: 44.0)
        .signInWithAppleButtonStyle(.black)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.54.47.png

StoreKit

appStoreOverlayが使えます。

サンプルコード

import SwiftUI
import StoreKit

struct SwiftUIView: View {
    @State var showOverlay:Bool = false
    var body: some View {
        Button("App Store Overlay") {
            self.showOverlay.toggle()
        }
        .appStoreOverlay(isPresented: $showOverlay) {
            SKOverlay.AppConfiguration(appIdentifier: "687721425", position: .bottom)
        }
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        return SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.46.41.png

AVKit

VideoPlayerが使えます。
ドキュメントには A view that displays the video content from a player object along with system-supplied playback controls. とあるんですが、tvOSだとコントロールが出ない感じです。

サンプルコード

import SwiftUI
import AVKit

struct SwiftUIView: View {
    let player: AVPlayer?
    var body: some View {
        VideoPlayer(player: player)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        return SwiftUIView(player: AVPlayer(url: URL(string: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!))
    }
}

プレビュー

スクリーンショット 2020-11-14 11.34.07.png

SceneKit

SceneView が使えます。scnファイルは各自用意してください。

サンプルコード

import SwiftUI
import SceneKit

struct SwiftUIView: View {
    let scene: SCNScene?
    var body: some View {
        SceneView(scene: scene)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        let scene = SCNScene(named: "Scene.scn")

        return SwiftUIView(scene: scene)
    }
}

プレビュー

スクリーンショット 2020-11-14 11.32.49.png

HomeKit

CameraViewが使えます。
HMCameraSource が必要になりますが、おそらくSwiftUIプレビューでは用意できないので、各自実機でご確認ください。

サンプルコード

import SwiftUI
import HomeKit

struct SwiftUIView: View {
    let cameraSource:HMCameraSource
    var body: some View {
        CameraView(source: cameraSource)
    }
}

画像

IMG_1F757207E2D1-1.jpeg

WatchKit

NowPlayingViewが使えます。

サンプルコード

import SwiftUI
import WatchKit

struct SwiftUIView: View {
    var body: some View {
        NowPlayingView()
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

プレビュー

スクリーンショット 2020-11-14 11.39.10.png

まとめ

つかおう!HomeKit!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Googleドライブからの埋め込み動画がSafariで閲覧できない

問題点

  • Webページに埋め込んだ Googleドライブ上の動画が、Safari で閲覧すると再生されない。
    • Chrome など、別のブラウザではふつうに再生できる。
    • YouTube にアップしたものを埋め込むと、Safari でも問題なく再生できる。
  • 動画のサムネイルは表示されるが、再生ボタンを押すと、下のように真っ黒になってしまい、再生できない。 image.png

(参考)Googleドライブ上の動画の埋め込み

  • 以前は、Googleドライブ上のコンテクストメニューから埋め込み用のURLを取得できたが、現在は若干面倒になっている。
  • Gooleドライブで取得できる共有用のURLで動画を閲覧し、そのページの右上のプルダウンメニューから「アイテムを埋め込む…」を選ぶとHTMLコードをコピーできる。
    • いちいちこの操作をする必要はなく、以下のように書けば埋め込める。
<iframe src="https://drive.google.com/file/d/{ファイルID}/preview" width="640" height="480"></iframe>
  • 埋め込み用のHTMLコードを取得するための方法は、ちょいちょい仕様が変わる。

解決法

  • Safariのセキュリティ設定に起因するので、サーバ側で回避することはできない。閲覧するユーザーに解決法の実行を促すしかない。

解決法1:別のブラウザで閲覧してもらう

  • Chromeなどを使ってもらう。

解決法2:Safariのセキュリティ設定を変更してもらう

  • macOSのSafariなら、環境設定 → プライバシー のタブを開き、Webサイトによるトラッキングの サイト越えトラッキングを防ぐ のチェックを外す。
    image.png

  • iOSのSafariなら、設定 → Safari の プライバシーとセキュリティ のブロックにある、 サイト越えトラッキングを防ぐ のチェックを外す。
    image.png

解決法3:ポップアウトして閲覧してもらう

  • 動画右上のボタンから別ウィンドウ(タブ)にポップアウトしてもらえば、閲覧可能です。
    • ただし、Web上に埋め込まれた動画が、クリックすると真っ黒になってしまうという、コスメティックにダメっぽい問題は解決されません。

image.png

素朴な疑問

  • 同じ Google 系の YouTube は問題なく閲覧できるのはどうしてなのか、謎。Googleドライブの動画機能は、YouTubeの機能制限版という雰囲気で、トラッキングとか YouTube の方が激しくやっていそうなものだが……
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む