Apple Engine

Apple, iPhone, iOS, その周辺のことについて

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」を押す。

f:id:x67x6fx74x6f:20180221181328p:plain

 

プロジェクト名を決めて「Next」を押して任意の場所に保存。

 

Command + R で実機にビルド。
(多分、シミュレータでも動作するが iCloud のIDやパスワードを入れるのが面倒なので)

 

画像ファイルを選択すると ViewController に遷移してファイル名が表示される。

f:id:x67x6fx74x6f:20180221183215g:plain

 

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 が設定されている。

f:id:x67x6fx74x6f:20180221181554p:plain

 

Document Types の編集

現状、画像ファイルが設定されているので修正。
今回はカスタムのファイルなのでなんども良いのだが、 Name を先ほど調べた「SceneKit Scene Document」に、 Types を「public.data」に設定している。

本来は Types を public.3d-content にしたいのだが、iOS で 3D の汎用ファイルがないため、汎用的な「public.data」を使用している。
テキストデータではないのはシーンファイルがバイナリの plist であるため。

閲覧だけなので document type properties は割愛

f:id:x67x6fx74x6f:20180221181631p:plain

 

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 を設定する

f:id:x67x6fx74x6f:20180221181712p:plain

 

新規作成時にプロジェクトのリソースにあるシーンファイルをコピーする

テンプレートのままだと、「書類を作成」のボタンをタップしても何も起こらないので、
「書類を作成」のボタンをタップ時にリソースのシーンファイルを 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)
    }
}

ビルド後、このアプリのフォルダの「書類を作成」のボタンか、ヘッダー右上の「+」ボタンを押すと、
リソースにあるシーンファイルが新規作成時のファイルとしてコピーされファイル情報がファイル情報を取得できるようになりファイル名が表示される。

f:id:x67x6fx74x6f:20180221183300g:plain

 

シーンファイルを表示する SCNView を設定する

Main.storyboard の SCNView 設定

Main.storyboard を開き、「Document View Controller Source」を選択。

f:id:x67x6fx74x6f:20180221181826p:plain

 

Object Library (Command + Control + Option + 3) から SCNView をドラックして、Docuemnt Outline の Stack View の上に配置。

ざっくり Auto Layout を設定。

f:id:x67x6fx74x6f:20180221181851p:plain

 

DocumentViewController.swift の設定

そして、DocumentViewController.swift に SCNView の IBOutlet を作成。

f:id:x67x6fx74x6f:20180221181910p:plain

 

DocumentViewController.swift の 以下のコードの下に

self.documentNameLabel.text = self.document?.fileURL.lastPathComponent

 

こちらを追加すると完成

self.scnView.scene = try? SCNScene(url: (self.document?.fileURL)!, options: [:])

 

f:id:x67x6fx74x6f:20180221183411g:plain

 

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 などを参照してもらえれば良いかと思われる。

iOS 11 Programming

iOS 11 Programming

  • 著者:堤 修一,吉田 悠一,池田 翔,坂田 晃一,加藤 尋樹,川邉 雄介,岸川 克己,所 友太,永野 哲久,加藤 寛人,
  • 製本版,電子版
  • PEAKSで購入する

 

サンプルコード

github.com