初めに
こんにちは、決済認証システム開発事業部の陳です。 会社では、iOS、Androidなどネイティブアプリ開発に携わっております。
巷ではChatGPT、Diffusion AIなどAIの活用について話題に上がっており、 様々なデバイス、サービスへ導入するなど試行錯誤が行われております。
流行りに乗る感じで、ネイティブアプリにPythonを導入する方法を解説したいと思います。 OpenAIを利用したサンプルアプリまで数回に分けて記事を投稿する予定です。 今回は第一弾になります。
BriefcaseよりiOS用のライブラリを生成
Briefcase - togaで、Pythonを導入した状態のiOSプロジェクトを作成できるので、必要なライブラリを取り出し既存のプロジェクトに導入するという流れになります。 docs.beeware.org
仮想環境を構築してBriefcaseのライブラリをインストールしてプロジェクトを作成します。 プロジェクト名はHellowWorldで大丈夫です。
python3 -m venv venv source venv/bin/activate briefcase new
プロジェクトのフォルダに移動し、iOS向けにプロジェクトを出力します。
cd helloworld briefcase create iOS
XcodeにPythonライブラリを導入
生成したプロジェクトのSupportフォルダをそのまま、導入先のプロジェクトに コピペします。
Briefcaseに関する作業はこれで終わりです。 次にXcodeに下記の設定でSupportのフォルダを追加します。
Python.xcframeworkも忘れずにLinkしてください
Python用ブリッジファイルの追加
Python.h (C言語)を利用するため、Objective-C File、Header Fileを追加します。
Build SettingにPythonBridge.hを登録します
テストコードを実装し、正常に動作するのか確認します。
// PythonBridge.h void bridgeTest(void); // PythonBridge.m void bridgeTest() { NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; NSLog(@"resourcePath: %@", resourcePath); }
NSLogよりアプリのインストール先が出力されるので、Supportの一式がコピーされているのか確認します。
PythonのライブラリまでPathを通す
Pythonを動かすためには、PYTHONHOMEを設定する必要があり、先ほどNSLogで出力した先までPathを通す必要があります。 BriefcaseのiOSプロジェクトより Supporting Files -> main.m を参考にPythonの環境を設定します。
// PythonBridge.h void initilaizePython(void); void testModuleFunction(void); // PythonBridge.m void initilaizePython() { PyPreConfig preconfig; PyConfig config; wchar_t *wtmp_str; NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; NSString *path; NSLog(@"resourcePath: %@", resourcePath); PyPreConfig_InitIsolatedConfig(&preconfig); PyConfig_InitIsolatedConfig(&config); preconfig.utf8_mode = 1; config.buffered_stdio = 0; config.write_bytecode = 0; config.module_search_paths_set = 1; // Python 初期化開始 Py_PreInitialize(&preconfig); // Python Home Path NSString* python_home = [NSString stringWithFormat:@"%@/Support/python-stdlib", resourcePath, nil]; wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); PyConfig_SetString(&config, &config.home, wtmp_str); PyMem_RawFree(wtmp_str); PyConfig_Read(&config); // Module Path path = [NSString stringWithFormat:@"%@/Support/python-stdlib", resourcePath, nil]; wtmp_str = Py_DecodeLocale([path UTF8String], NULL); PyWideStringList_Append(&config.module_search_paths, wtmp_str); PyMem_RawFree(wtmp_str); // Python 初期化完了 Py_InitializeFromConfig(&config); } void finalizePython() { Py_Finalize(); }
ViewController -> viewDidLoad で上記処理をテストし、正常に動作することを確認します
initilaizePython() finalizePython()
Pythonを実際に動かす。
Supportフォルダと同じ要領で、PySourceを追加します。
// pythonTest.py def printTest(): print("Load Python Success")
PySourceにPathを通します
// PythonBridge.h void testModuleFunction(void); // PythonBridge.m void initilaizePython() { ~~~ path = [NSString stringWithFormat:@"%@/Support/python-stdlib", resourcePath, nil]; wtmp_str = Py_DecodeLocale([path UTF8String], NULL); PyWideStringList_Append(&config.module_search_paths, wtmp_str); PyMem_RawFree(wtmp_str); // PySource path = [NSString stringWithFormat:@"%@/PySource", resourcePath, nil]; wtmp_str = Py_DecodeLocale([path UTF8String], NULL); PyWideStringList_Append(&config.module_search_paths, wtmp_str); PyMem_RawFree(wtmp_str); ~~~ } void testModuleFunction() { PyObject *module = PyImport_ImportModule("pythonTest"); PyObject *function = PyObject_GetAttrString(module, "printTest"); PyObject_CallNoArgs(function); }
ViewController -> viewDidLoad で上記処理をテストします
initilaizePython() testModuleFunction() finalizePython()
consoleにprintされているはずです。 結果は自身で試してみてください。
まとめ
簡単なPythonのスクリプトを実行できるまでの流れは以上になります。実用には、様々なライブラリをimport必要があり、次回の記事で特集する予定です。
採用リンク tecotec.co.jp