- 投稿日:2020-04-01T14:36:53+09:00
【iOS】Dropbox iOS13対応
はじめに
・iOS13用にDropboxを対応したところ、ハマったので備忘録として記載。
環境
xcode11.0
swift 5.0.1
iOS13これまで
・チュートリアル通りに進むと
AppDelegate.swiftfunc application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { if let authResult = DropboxClientsManager.handleRedirectURL(url) { switch authResult { case .success: print("Success! User is logged into Dropbox.") case .cancel: print("Authorization flow was manually canceled by user!") case .error(_, let description): print("Error: \(description)") } } return true }と記載していた。
iOS13ではSceneDelegate.swiftに移譲された為、変更が必要になる。これから
・SceneDelegate.swiftへ以下を記載。
SceneDelegate.swiftfunc scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { // コールバックで来たURLの取得 guard let url = URLContexts.first?.url else { return } if let authResult = DropboxClientsManager.handleRedirectURL(url) { switch authResult { case .success: print("Success! User is logged into Dropbox.") case .cancel: print("Authorization flow was manually canceled by user!") case .error(_, let description): print("Error: \(description)") } } return }まとめ
・iOS13とそれ以前のiOSを対応させるように作成した為、AppDelegateが原因であることに気づくのに時間がかかった。
大型アップデート後の情報収集は怠ってはならない教訓になりました。
- 投稿日:2020-04-01T12:19:57+09:00
Windows10のUbuntu18.04でSwift 5.2.1とVapor 4.0.0へアップデート
環境をアップデートします。
以前の環境はノートPCと共にお亡くなりになりましたが、再度同環境を構築してVaporの動作を確認していました。しかしながらテンプレートがどうも上手く動かないようで、どうせ調べるなら最新がいいなぁと思いVapor4系に更新することにしました。
Swift 5.2.1
Vapor4系はSwift5.2以上が必要なので、まずSwiftを更新します。
タイムリーなことに、2020年3月30日に5.2.1がリリースされていました。Ubuntu 18.04用をダウンロードして展開します。
5.1.5の時と同じように/usr/local下へコピーしてパスを通します。
.bashrcを編集
#export PATH=/usr/local/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin:$PATH export PATH=/usr/local/swift-5.2.1-RELEASE-ubuntu18.04/usr/bin:$PATHダメだった時に備えて、Swift5.1.5も残しておきます。
source .bashrc swift --versionSwift5.2.1が使えるようになりました。
Vapor4
Vapor4.0のヘルプを見ながらVapor Toolboxをインストールします。
githubから取ってきて、ビルドします。
git clone https://github.com/vapor/toolbox.git cd toolbox git checkout は最新を使うのでやらない swift build -c release --disable-sandboxエラー
Fetching https://github.com/tanner0101/mustache.git Fetching https://github.com/apple/swift-log.git Fetching https://github.com/vapor/console-kit.git Fetching https://github.com/apple/swift-nio.git Fetching https://github.com/jpsim/Yams.git Cloning https://github.com/jpsim/Yams.git Resolving https://github.com/jpsim/Yams.git at 2.0.0 Cloning https://github.com/vapor/console-kit.git Resolving https://github.com/vapor/console-kit.git at 4.0.0-rc.1 Cloning https://github.com/apple/swift-nio.git Resolving https://github.com/apple/swift-nio.git at 2.15.0 Cloning https://github.com/apple/swift-log.git Resolving https://github.com/apple/swift-log.git at 1.2.0 Cloning https://github.com/tanner0101/mustache.git Resolving https://github.com/tanner0101/mustache.git at 0.1.0 error: missing LinuxMain.swift file in the Tests directory空でもいいという噂もありましたが、LinuxMain.swift をTests下に以下な感じで作ってみます。
import XCTest @testable import MonoGeneratorTests XCTMain([ testCase(GeneratorTests.allTests), ])もう一回ビルドすると、なにやらWarningが出てますが、とりあえずvaporは出来ています。
/home/arimitsu/toolbox/.build/checkouts/Yams/Sources/Yams/Emitter.swift:338:32: warning: initialization of 'UnsafeMutablePointer<yaml_version_directive_t>' (aka 'UnsafeMutablePointer<yaml_version_directive_s>') results in a dangling pointer versionDirective = UnsafeMutablePointer(&versionDirectiveValue) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/arimitsu/toolbox/.build/checkouts/Yams/Sources/Yams/Emitter.swift:338:53: note: implicit argument conversion from 'yaml_version_directive_t' (aka 'yaml_version_directive_s') to 'UnsafeMutablePointer<yaml_version_directive_t>' (aka 'UnsafeMutablePointer<yaml_version_directive_s>') produces a pointer valid only for the duration of the call to 'init(_:)' versionDirective = UnsafeMutablePointer(&versionDirectiveValue) ^~~~~~~~~~~~~~~~~~~~~~ /home/arimitsu/toolbox/.build/checkouts/Yams/Sources/Yams/Emitter.swift:338:53: note: use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope versionDirective = UnsafeMutablePointer(&versionDirectiveValue) ^ [22/22] Linking vapor./.build/release下に出力された vapor を/usr/local/binの下へコピーしてヘルプを表示して確認する。
vapor --helpvapor --version これは無しプロジェクト作成
新規にプロジェクトを作ってみます。
vapor-beta new hello -nん?
vapor-betaは無いだろうなぁ
-nはいらないかなVapor4.0.0なのでhello「4」の以下でいきます。
vapor new hello4Fluentはとりあえず使いませんので「n」で。
Cloning template... name: hello4 Would you like to use Fluent? y/n> n fluent: No Generating project files + Package.swift + main.swift + configure.swift + routes.swift + .gitkeep + AppTests.swift + Dockerfile + docker-compose.yml + .gitignore + .dockerignore Creating git repository Adding first commitここでGitのエラーが出るかもしれません。その前にGitのユーザー名とメールアドレスを登録しておきましょう。
git config --global user.name [名前] git config --global user.email [メールアドレス]cd hello4 vapor buildネットで調べたところ、同じようにコアダンプしている人が質問してました。
- 質問者 「Vaporでビルドするとコアダンプするんだけど、どうしたらいい?」
- 回答者 「Swift試してみた?」
- 質問者 「動いた!」
以上終わり?swiftでいいのかね?
swift build
またか・・・
上でつくったLinuxMain.swift をTests下にコピーしてやります。swift buildできた!
swift runブラウザからも動作を確認できました。
途中でいろいろやったこと
ネットで調べてやってみましたがが、とりあえず必要なかったです。
Package.swift
プラットフォーム指定がmacOSだからダメなんじゃないの?でコメントアウト
dependenciesで指定しているパッケージのfromが最新のものを固定で指定してみる
toolbox
toolboxのPackage.swiftでも、同様にやってみる。
toolboxのビルドで-Xswiftcをつけてみる、-g(何これ?)をつけてみる
最後に
ビルドのWarningが気になりますがerrorではないので致命的ではないし、とりあえず動くようにはなりましたので、テンプレートの確認に戻ります。
動くのかな?
- 投稿日:2020-04-01T09:33:43+09:00
独自プロパティリスト(plist)を利用する
iOSアプリで独自plist(プロパティリスト)を作って使いたい時のメモ。
※よくある、APIのURLとかその他アプリに特化した設定などに使用
※他の方がわかりやすく書いてくれているのもあるのでメモ程度plistの作成
まずはお目当てのplistを作成します。
- File→New→File(cmd+N)で新規作成画面を表示
- Property Listを選択、名前(今回はApp.plist)を決めて作成
作成できたら、適当に値を設定しましょう。
今回はよくあるURLを記載します作ったplistの読み込み
先程作ったApp.plistを読み込むコードが以下になります。
var property: Dictionary<String, Any> = [:] // App.plistのパス取得 let path = Bundle.main.path(forResource: "App", ofType: "plist") // App.plistをDictionary形式で読み込み let configurations = NSDictionary(contentsOfFile: path!) if let datasourceDictionary: [String : Any] = configurations as? [String : Any] { property = configurations } // キーを指定して、値の取得 let url = property["url"] as! String print(url)データ取得部分も含めてクラス化
読み込み、データ取得を毎度書くのは無駄よってことで
クラス化します。App.swiftclass App { var property: Dictionary<String, Any> = [:] init() { // App.plistのパス取得 let path = Bundle.main.path(forResource: "App", ofType: "plist") // App.plistをDictionary形式で読み込み let configurations = NSDictionary(contentsOfFile: path!) if let datasourceDictionary: [String : Any] = configurations as? [String : Any] { property = datasourceDictionary } } /// 指定されたキーの値を取得する /// - Parameter key: plistのキー func getString(_ key: String) -> String? { guard let value: String = property[key] as? String else { return nil } return value } }さて、これで利用できるようになりました。
では実際に呼び出してみましょう。var app = App() print(app.getStirng("url"))Appクラスをシングルトンにしてみる
シングルトンにすることで、読み込みを一回だけにしてあとはインスタンス再利用する形にします。
以下コードを追加static let shared: App = { let instance = App() return instance }()全体
App.swiftclass App { var property: Dictionary<String, Any> = [:] static let shared: App = { let instance = App() return instance }() private init() { // App.plist取得 let path = Bundle.main.path(forResource: "App", ofType: "plist") let configurations = NSDictionary(contentsOfFile: path!) if let datasourceDictionary: [String : Any] = configurations as? [String : Any] { property = datasourceDictionary } } /// 指定されたキーの値を取得する /// - Parameter key: plistのキー func getString(_ key: String) -> String? { guard let value: String = property[key] as? String else { return nil } return value } }さて、これで利用方法を変更します。
var app = App.shared print(app.getStirng("url"))これでアプリ独自プロパティも怖くない!!
次回は、これを環境別に設定できるようにしたいと思います。参考
- 投稿日:2020-04-01T08:49:06+09:00
Transformを使用して簡単に視差効果を表現する
今回はアプリの初回チュートリアルなどでスクロールをカッコよく見せる演出として使われるパララックス(視差効果)を表現する実装をご紹介します。
今回のものはサンプルなので見た目はイマイチですが、参考程度にどうぞ。完成イメージ
白い正方形のViewには視差効果を与えておらず、1ページ目の青いLabel、2ページ目の黒いLabelに視差効果を与えています。
青のLabelと白いViewのスクロール量が少しずれていることがわかると思います。実装概要
- UIScrollViewでページングをする横スクロールを作成します
- UIScrollView内にはUIStackViewを配置し、任意のページ分のコンテンツを追加してスクロールできるようにします。
- 各ページのUIViewのtransform, alphaにアクセスして、スクロール量に応じて値を変化させます。
View階層
実装
今回はUI実装の簡略化のためにSnapKitというライブラリを使用させていただきます。
import UIKit import SnapKit final class ParallaxViewController: UIViewController { let scrollView: UIScrollView = { let scroll = UIScrollView() scroll.isPagingEnabled = true return scroll }() let stackView: UIStackView = { let stack = UIStackView() stack.axis = .horizontal stack.alignment = .fill stack.backgroundColor = .purple return stack }() let containers: [LabelContainer] = [ LabelContainer(labelColor: .blue), LabelContainer(labelColor: .black) ] private var contentOffsetObservation: NSKeyValueObservation? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white configureScrollView() contentOffsetObservation = scrollView.observe(\.contentOffset) { [weak self] scrollView, _ in guard let me = self else { return } me.containers.enumerated().forEach { index, container in let distanceContainerToLabel = container.frame.origin.x - scrollView.contentOffset.x // スクロール量に応じてLabelの表示位置をずらす container.label.transform = .init( translationX: distanceContainerToLabel * -0.3, y: .zero ) let limit = me.scrollView.bounds.width // スクロール量に応じてLabelの透明度を変化させる container.alpha = { switch distanceContainerToLabel { case -limit..<0, 0..<limit: return 1 - abs(distanceContainerToLabel) / limit default: return .zero } }() } } } private func configureScrollView() { view.addSubview(scrollView) scrollView.snp.makeConstraints { $0.top.left.right.equalToSuperview() $0.height.equalTo(300) } scrollView.addSubview(stackView) stackView.snp.makeConstraints { $0.edges.height.equalToSuperview() } containers.forEach { container in stackView.addArrangedSubview(container) container.snp.makeConstraints { $0.width.equalTo(view.snp.width) } } let box = UIView() box.backgroundColor = .white scrollView.addSubview(box) box.snp.makeConstraints { $0.width.height.equalTo(200) $0.center.equalToSuperview() } } } final class LabelContainer: UIView { let label: UILabel init(labelColor: UIColor) { label = makeLabel(color: labelColor) super.init(frame: .zero) addSubview(label) label.snp.makeConstraints { $0.edges.equalToSuperview() } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } fileprivate func makeLabel(color: UIColor) -> UILabel { let label = UILabel() label.text = Array(repeating: "LABEL", count: 100).joined() label.textAlignment = .center label.numberOfLines = 0 label.textColor = .white label.backgroundColor = color return label }