【Swift】UIImagePickerControllerでカメラ機能を追加する

swift-og

【Swift】UIImagePickerControllerでカメラ機能を追加する

import AssetsLibrary

// MARK: - UIImagePickerControllerDelegate
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

func showAlbum() {

        DeviceAuthorization.isAlbumAuthorization { (status: PHAuthorizationStatus) in
            if status != PHAuthorizationStatus.authorized {
                self.showDeviceDeniedAlert(title: "写真を起動できません", message: "写真を起動することができませんでした")
                return
            }

            let imagePickerVc = UIImagePickerController()
            imagePickerVc.sourceType = UIImagePickerControllerSourceType.photoLibrary
            imagePickerVc.delegate = self
            self.present(imagePickerVc, animated: true, completion: nil)
        }
    }

    func showCamera() {
        DeviceAuthorization.isCameraAuthorization(callback: { (status: AVAuthorizationStatus) in
            if status != AVAuthorizationStatus.authorized {
                self.showDeviceDeniedAlert(title: "カメラを起動できません", message: "カメラを起動することができませんでした")
                return
            }

            let imagePickerVc = UIImagePickerController()
            // シュミレータでは'Source type 1 not available'と実行時エラーとなる
            imagePickerVc.sourceType = UIImagePickerControllerSourceType.camera
            imagePickerVc.delegate = self
            self.present(imagePickerVc, animated: true, completion: nil)
        })
    }

    // image選択時
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        if let url = info[UIImagePickerControllerReferenceURL] as? URL {
            self.viewModel?.setImagePath(imagePath: url.absoluteString)
            self.applicationService?.onChangeImagePath(imagePath: url.absoluteString)
        } else if let cameraImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
            var localId = ""
            PHPhotoLibrary.shared().performChanges({
                let request = PHAssetChangeRequest.creationRequestForAsset(from: cameraImage)
                localId = request.placeholderForCreatedAsset?.localIdentifier ?? ""
            }, completionHandler: { [weak self] (success: Bool, error: Error?) in
                if error != nil {
                    self?.toast(message: "画像の保存に失敗しました")
                    return
                }
                if !localId.isEmpty {
                    if let result = PHAsset.fetchAssets(withLocalIdentifiers: [localId], options: nil).firstObject {
                        self?.getURLofPhoto(mPhasset: result) { [weak self] (url: URL?) in
                            if let url = url {
                                self?.viewModel?.setImagePath(imagePath: url.absoluteString)
                                self?.applicationService?.onChangeImagePath(imagePath: url.absoluteString)
                            }
                        }
                    }
                }
            })
        }

        picker.dismiss(animated: true, completion: nil)
    }

    private func getURLofPhoto(mPhasset: PHAsset, callback: @escaping (URL?) -> Void) {

        if mPhasset.mediaType == .image {

            let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
            options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
                return true
            }

            mPhasset.requestContentEditingInput(with: options) {
                (contentEditingInput: PHContentEditingInput?, info: [AnyHashable : Any]) in

                callback(contentEditingInput?.fullSizeImageURL?.absoluteURL)
                return
            }
        }
        callback(nil)
    }

    private func showDeviceDeniedAlert(title: String, message: String) {

        let alert: UIAlertController = UIAlertController(
            title: title,
            message: message,
            preferredStyle:  UIAlertControllerStyle.alert)

        let goSettingAction: UIAlertAction = UIAlertAction(title: "写真とカメラの設定を開く", style: UIAlertActionStyle.default, handler: {
            (action: UIAlertAction!) -> Void in

            if let url = URL(string:UIApplicationOpenSettingsURLString) {
                if #available(iOS 10.0, *) {
                    UIApplication.shared.open(url, options: [:], completionHandler: nil)
                } else {
                    UIApplication.shared.openURL(url)
                }
            }
        })

        let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertActionStyle.cancel, handler: {
            (action: UIAlertAction!) -> Void in
        })

        alert.addAction(goSettingAction)
        alert.addAction(cancelAction)

        self.present(alert, animated: true, completion: nil)
    }

}

備忘録
  • plistに
<key>NSCameraUsageDescription</key>
<string>チャットへ画像を投稿する際に利用します</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>チャットへの画像投稿やアイコンを設定する際に利用します</string>
<key>UILaunchStoryboardName</key>

を書いておく必要があります。

  • エミュレータだとUIImagePickerControllerSourceType.cameraで terminating with uncaught exception of type NSExceptionのエラーが発生しますが、*** First throw call stack: より前の*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:'Source type 1 not available'とあります。
    実機であれば問題ないようです。

【参考資料】

詳解Swift 第3版 [ 荻原 剛志 ]

詳解Swift 第3版 [ 荻原 剛志 ]

価格:3,456円
(2017/1/3 01:58時点)
感想(0件)

【スポンサーサイト】


広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中