こんにちは、エンジニアのオオバです。
Unityでゲーム開発をしていると プラットフォーム固有機能へアクセス をしたくなります。Unity側が機能をサポートしていない場合、困ってしまいます。
そこで登場するのが 「ネイティブプラグイン」 です。
各プラットフォームごとにネイティブプラグインを実装することで Unityがサポートしていない機能にアクセスできる ようになります。
本記事では「iOS端末内のファイルの有無を調べる」シンプルなネイティブプラグインを作ってみようと思います。ネイティブプラグイン開発が初めての方にも学びやすい教材だと思うので、実際にコードを書きながら試してもらえればと思います。
またイチからiOSネイティブプラグインを勉強したい方はこちらの記事から読んでみることをおすすめします。
👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!
iOS端末内ファイルを確認する3つの実装手順
今回作成するものはファイル「img.png」が ドキュメントディレクトリ内に保存されているかどうか を確認するネイティブプラグインです。3ステップで実装していきます。
①ファイル(img.png)までのパスを作成
②NSFileManagerを取得
③fileExistsAtPathメソッドを実行
ステップ①ファイルまでのパスを作成
最初にやるべきことはファイルまでのパス作成です。ドキュメントディレクトリまでのパスとファイル名をくっつけたパスを作成します。
// ドキュメントディレクトリまでのパス取得
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
// img.pngまでのパスを作成
NSString *filePath = [[dirPaths objectAtIndex:0]
stringByAppendingPathComponent:@"img.png"];
コードの解説をしていきます。
- NSSearchPathForDirectoriesInDomains・・・ディレクトリの検索関数
- NSDocumentDirectory・・・ドキュメントディレクトリ指定
- NSUserDomainMask・・・現在のユーザーのホームディレクトリを指す
- YES・・・フルパスで返却
後半のコードについて。
- [dirPaths objectAtIndex:0] ・・・配列dirPathsの1つ目の要素を取得
- stringByAppendingPathComponent・・・パスの連結
こんな感じです。
今回確認するimg.pngファイルパスが変数「filePath」に格納されたということです。
なぜNSSearchPathForDirectoriesInDomainsは角括弧[]を使わないのか?
少しここで余談です。Objective-Cのメソッド呼び出しは角括弧を使用しますが、 NSSearchPathForDirectoriesInDomains
はカッコ()で呼び出しています。
理由は NSSearchPathForDirectoriesInDomains
がC言語だからです。 NSSearchPathForDirectoriesInDomainsはObjective-Cではない ということ。だからカッコ()で処理を記述しているのです。
ステップ②NSFileManagerを取得
次にやるべきことは NSFileManagerインスタンスの取得 です。
NSFileManager *fileManager = [NSFileManager defaultManager];
「NSFileManager」はファイル、フォルダを管理するクラスです。アプリ内のファイルやディレクトリを操作することができます。
defaultManager
関数ででNSFileManagerインスタンスを取得します。
ステップ③fileExistsAtPathメソッドを実行
最後の3ステップはいよいよファイルの有無を確認します。実装方法はとても簡単です。
NSFileManager
インスタンスの fileExistsAtPath
関数を実行するだけ。
BOOL isExist = [fileManager fileExistsAtPath:filePath];
ステップ①、②で用意したファイルパスとNSFileManagerを使ってファイルの確認が可能です。
fileExistsAtPath
メソッドを実行すると、ファイルが存在すればYes、存在しなければNoで返ってきます。
Unityから呼べるようにネイティブプラグイン化
今のままではただのネイティブコードなので、C#から呼べるように加工していきます。ネイティブプラグインの作り方を覚えていますでしょうか?そうです。処理を extern "C"
で囲むんでしたね。
ネイティブプラグインの基本はこちらの記事を参考にしてみてください。
#import <Foundation/Foundation.h>
extern "C" {
bool FileExistsAtPath(const char* filename)
{
// ドキュメントディレクトリの取得
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[dirPaths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithUTF8String:filename]];
// NSFileManagerでファイルの存在確認
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isExist = [fileManager fileExistsAtPath:filePath];
NSLog(@"FileExistsAtPath: %d", isExist);
return isExist;
}
}
このように加工したFileCheckerPlugin.mmというファイル名でUnity内の Assets/Plugins/iOS/
に保存します。
次にC#側の処理を記述していきます。こんな感じでネイティブプラグイン側の処理を呼び出すように実装しました。
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class FileChecker : MonoBehaviour
{
#if UNITY_IOS && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern bool FileExistsAtPath(string filename);
#else
private static bool FileExistsAtPath(string filename) { return false; } // エディタやAndroidではfalseを返す
#endif
public void CheckFile()
{
string filename = "img.png"; // 確認するファイル名
bool exists = FileExistsAtPath(filename);
Debug.Log($"File exists: {exists}");
}
void OnGUI()
{
// デバッグボタン
if (GUILayout.Button("Check", GUILayout.Height(300f), GUILayout.Width(600f)))
{
CheckFile();
}
}
}
C#側からfilename変数を渡して拡張性を上げています。この状態でXcodeでビルドして確認してみてください。
まとめ
Objective-Cを使ってドキュメントディレクトリ内のファイル有無を確認してきました。
ポイントはこちら。
「NSFileManagerのfileExistsAtPathメソッドを使う」
これだけ覚えておけば大丈夫です。
ストレージ内のファイル有無確認はよく発生します。ぜひネイティブプラグインの作り方とセットで覚えておきましょう。
今回紹介したサンプルを元にObjective-Cの文法学習記事を執筆しました。

筆者のXをフォローしよう
Unityオブジェクトの描画順の制御って難しいですよね。
この度、Unityの描画順を体系的に学べる「Unity描画順の教科書」を執筆しました。
Unityの描画順を基礎から学びたい方はぜひ確認してみてください!
→ Unity描画順の教科書
最後まで読んでいただきありがとうございました!
すばらしいiOSネイティブプラグインライフをお過ごしください。