Document Base App テンプレートを使って SceneKit のシーンファイル(.scn)簡易ビューワーをつくる for iOS
macOS の場合、ファイル選択しスペースキーを押すと QuickLook 経由でシーンファイルのプレビューが閲覧できるのだが、
iOS の場合設定がされていないので、極めて簡単な表示するだけのビューワーをつくってみる。
iOS の Document Based App とは?
iPhone は登場後、しばらくはユーザー側でファイルを直接扱うことができず、
iPad が登場した際に Pages、Numbers、Keynote など制作向けのアプリが登場し、
UIDocumentInteractionController が導入されユーザーからファイルを扱うことができるようになった。
iOS 11 では Files(ファイル)アプリが登場し、macOS の Finder と同様な操作ができるようになった。
Document Based App は Files の UI を使用でファイルを選択しアプリが動作するという、初期の iOS の思想とは異なるタイプのアプリとなっている。
Pages、Numbers、Keynote や GrageBand, ペイントソフトなど今までもこのタイプものはあったが、
今回は専用の API が用意されるようになった。
また、iOS 10 の iCloud Drive アプリではできなかった各アプリの Documents のフォルダにアクセスできるようになっている
Document Based App の主な動作
- Files(ファイル)アプリのような ViewController が起点となりファイルを選択し開く
- 開くと閲覧や作業用の ViewController に遷移
基本的にはファイルは自動保存させる必要があり、このタイプの Apple 製のアプリは自動で保存されているはずである。
また、特定のファイルを開くため、アプリでファイルの関連付けを行う必要がある。
Document Based App テンプレート
振る舞い
Files アプリのような UI が表示され画像を選択するとファイル名が表示される。
Open-in-place の設定もされているため、アクションシートなどからサポート対象にしたファイルを開くことができる。
つくってみる
Xcode 9 を起動し、Welcome to Xcode のパネルの「Create a new Xcode project」か Command + Shift + N を押して、 新しいプロジェクトのテンプレート選択画面を表示する。
「Document Based App」テンプレートが表示されていると思われるので選択して「Next」を押す。
プロジェクト名を決めて「Next」を押して任意の場所に保存。
Command + R で実機にビルド。
(多分、シミュレータでも動作するが iCloud のIDやパスワードを入れるのが面倒なので)
画像ファイルを選択すると ViewController に遷移してファイル名が表示される。
Document Based App テンプレートを編集してシーンファイルを表示する
流れ
- シーンファイルの情報を調べ関連付けを行う
- 新規作成時にプロジェクトのリソースにあるシーンファイルをコピーする
- シーンファイルを表示する SCNView を設定する
シーンファイルの情報を調べ関連付けを行う
シーンファイルの情報を調べる
ファイルの関連付けを行うためファイルの設定をする。
今回はあまり必要ないのだが、一応 macOS 側でシーンファイル(.scn)が関連付けられているため、ターミナルからファイルを調べる。
ターミナルで何らかのシーンファイルがある階層までき、以下を入力。
mdls ファイル名
文字列が羅列されるのでコンテントタイプと名前に注目。
kMDItemContentType = "com.apple.scenekit.scene" kMDItemContentTypeTree = ( "public.item", "public.content", "com.apple.scenekit.scene", "public.data", "public.3d-content" ) ・ ・ ・ kMDItemKind = "SceneKit Scene Document"
シーンファイルの UTI として「com.apple.scenekit.scene」、
ファイルタイプとして「public.3d-content」、
ファイルの種類として「SceneKit Scene Document」が割り当てられている。
シーンファイルの情報を設定する
プロジェクトのターゲットで自分のアプリを選択し上のタブの「Info」を選択。
現状では Document Types と Imported UTIs が設定されている。
Document Types の編集
現状、画像ファイルが設定されているので修正。
今回はカスタムのファイルなのでなんども良いのだが、
Name を先ほど調べた「SceneKit Scene Document」に、
Types を「public.data」に設定している。
本来は Types を public.3d-content にしたいのだが、iOS で 3D の汎用ファイルがないため、汎用的な「public.data」を使用している。
テキストデータではないのはシーンファイルがバイナリの plist であるため。
閲覧だけなので document type properties は割愛
Exported UTIs の編集
Document Types の下にある Exported UTIs 編集してみる。
以下を設定。
設定名 | 値 |
---|---|
Description | SceneKit Scene Document |
Identifier | com.apple.scenekit.scene |
Conforms to | public.data |
関連づける拡張子を Additional exported UTI properties を以下に設定
UTTypeTagSpecification (Dictionary) > public.filename-extension (Array) > Item 0 (String) で scn を設定する
新規作成時にプロジェクトのリソースにあるシーンファイルをコピーする
テンプレートのままだと、「書類を作成」のボタンをタップしても何も起こらないので、
「書類を作成」のボタンをタップ時にリソースのシーンファイルを Documents フォルダーにコピーする。
DocumentBrowserViewController.swift を開き、 以下の中身を修正
func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) { ... }
こちらに変更
func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) { if let url = Bundle.main.url(forResource: "max", withExtension: "scn") { importHandler(url, .copy) } else { importHandler(nil, .none) } }
ビルド後、このアプリのフォルダの「書類を作成」のボタンか、ヘッダー右上の「+」ボタンを押すと、
リソースにあるシーンファイルが新規作成時のファイルとしてコピーされファイル情報がファイル情報を取得できるようになりファイル名が表示される。
シーンファイルを表示する SCNView を設定する
Main.storyboard の SCNView 設定
Main.storyboard を開き、「Document View Controller Source」を選択。
Object Library (Command + Control + Option + 3) から SCNView をドラックして、Docuemnt Outline の Stack View の上に配置。
ざっくり Auto Layout を設定。
DocumentViewController.swift の設定
そして、DocumentViewController.swift に SCNView の IBOutlet を作成。
DocumentViewController.swift の 以下のコードの下に
self.documentNameLabel.text = self.document?.fileURL.lastPathComponent
こちらを追加すると完成
self.scnView.scene = try? SCNScene(url: (self.document?.fileURL)!, options: [:])
GIF のスクリーンショットでのアイコンがおかしい
本来は iPad と iPhone で各 small と Large の画像を設定する必要があり、設定されていないため Slack のアイコンが設定されてしまっている。
次の XCode 9.3 では1枚の設定だけでよく、今回は面倒なので複数画像作っていないためこうなってしまっている。
注意点
上記の GIF を見るとわかるがテクスチャが適応されていない。
シーンファイルで書かれているテクスチャのパスと合わせる必要があり、このままではテクスチャ画像のファイルを適応するのが難しい。
今回のものは iCloud を使用するため、以前のような iTunes からファイルを扱うものとはファイルが保存される場所が異なるので注意。 また、iTunes からアクセスする場合は以前のように info.plist で Application supports iTunes file sharing (UIFileSharingEnabled) を YES にする必要がある。
まとめ
まだまだ設定しなければいけないものがあるが、Document Base App テンプレートを使用すると割と簡単にファイルを扱うアプリができるかと。
今回は、挙動の詳細やファイルのサムネールや QuickLook などの設定はしていないため、iOS 11 Programming などを参照してもらえれば良いかと思われる。