iOS 項目中如何使用 Python


我所在的公司對項目編譯后的大小和資源文件有嚴格的要求,每次集成發版對於包體積的增量都是有嚴格的控制,因此,如何減少包體積是每一個研發都需要考慮的。

對於包體積大小我們可以從資源文件和編碼來控制,如何減少項目編譯文件的大小,只能從代碼層面去進行一些優化,如規范代碼,合理的使用組合、繼承等設計模式。對於資源文件,如圖片我們可以進行壓縮后在集成。下面就是如何利用python對項目中的使用的圖片進行檢測並實現在線壓縮、上傳等功能。

正確引入 Python

Python 庫本身就支持 C 直接調用,只要我們能正確的引入即可。git上查找了下,果然已經有人給我們造好了輪子點這個鏈接,作者已經把對應版本 python 壓縮成 zip 並上傳,可直接下載解壓使用,當然我們也可以使用提供的 makefile 腳本自行編譯。同時作者還提供了一個快速創建iOS項目的模版點這個鏈接以下是記錄使用過程中的一些問題。

模版項目的安裝

下載作者提供的模版項目到本地點這個鏈接,查看作者提供的README.rst 文件,兩個步驟快速生成模版項目(我是使用自己手動創建的項目)

step1 執行 $ pip install cookiecutter 安裝 cookiecutter 插件

step2 執行 $ cookiecutter https://github.com/pybee/Python-iOS-template --checkout 3.7 安裝指定版本的python

生成的項目的整體目錄結構如下所示

 
0.png

3.8 版本 'cpython/initconfig.h' file not found 錯誤

目前最新的Python版本已經是3.8了,本着使用最新版本的原則,下載了3.8版本,解壓后引入工程,
編譯項目出現如下錯誤:

 
1.png

通過錯誤提示和頭部標識,我們發現這個文件不能直接被引用使用,在看下所有的 cpython 目錄下文件,除了initconfig.h 文件其他都有 this header file must not be included directly 標識,既然不能直接 included 直接干掉整個 cpython 目錄除 initconfig.h 的所有文件。再次編譯發現錯誤如下

 
2.png

在查看python headers 目錄下的所有文件,發現還有外層還有一個 pystate.h 文件,里面有一個對 cpython 目錄除 pystate.h 引用,但是剛剛已經被我們刪了

 
3.png

刪除也無法解決問題,說明該方式不對。查看了下issues里面的問題列表,也沒有發現該問題和解決方法,既然高版本不行,只能使用3.7了。

3.7 版本

替換項目中的python相關文件,直接編譯項目這次更離譜22個錯誤

 
4.png

查看錯誤會發現這些報錯都是Python目錄的 Resource/lib 文件下的文件,直接把該文件目錄刪除再次運行項目,這次運行成功了。完整的項目截圖如下所示

 
5.png

ps記得引入 libz.tdblibsqlite3.tdb 兩個模塊。

代碼嘗試 No module named 'encodings' 錯誤

直接將模版項目中main文件的代碼粘貼復制到自己項目中,運行項目這次出現了如下錯誤

 
6.png

錯誤是越來越多了,分析下錯誤提示發現是sqlite3庫問題,檢查下項目中如下的配置位置,發現是libz.tdblibsqlite3.tdb 兩個模塊沒有被導入,按下圖正確導入

 
7.png

再次運行項目,項目運行起來,但是新的錯誤又出現了

 
8.png

python在初始化的時候失敗了沒有找到 encodings 模塊,想到前面刪除的 Resource/lib 文件目錄,那么還是我們對模塊引入的方式有問題,從網上找了下 iOS 工程中調用Python方法,看到這篇文章有關於Home路徑的設置,下載了作者提供的代碼,發現可以把該模塊制作成 bundle模塊引入項目,並修改原代碼中關於 python_home 項目終於正確的運行起來了,修改刪除無用的代碼,並創建測試 main.py 文件,控制台成功打印出日志

 
9.png

完整的 main.m 代碼

#import "AppDelegate.h" #import "Python.h" #include <dlfcn.h> int main(int argc, char *argv[]) { int ret = 0; unsigned int I; NSString *tmp_path; NSString *python_home; NSString *python_path; wchar_t *wpython_home; const char* nslog_script; const char* main_script; wchar_t** python_argv; @autoreleasepool { NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; // Special environment to prefer .pyo; also, don't write bytecode // because the process will not have write permissions on the device. putenv("PYTHONOPTIMIZE=1"); putenv("PYTHONDONTWRITEBYTECODE=1"); putenv("PYTHONUNBUFFERED=1"); // Set the home for the Python interpreter python_home = [NSString stringWithFormat:@"%@/PythonEnv.bundle/Resources", resourcePath, nil]; NSLog(@"PythonHome is: %@", python_home); wpython_home = Py_DecodeLocale([python_home UTF8String], NULL); Py_SetPythonHome(wpython_home); // Set the PYTHONPATH python_path = [NSString stringWithFormat:@"PYTHONPATH=%@/Library/Application Support/com.example.jddd/app:%@/Library/Application Support/com.example.jddd/app_packages", resourcePath, resourcePath, nil]; NSLog(@"PYTHONPATH is: %@", python_path); putenv((char *)[python_path UTF8String]); // iOS provides a specific directory for temp files. tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; putenv((char *)[tmp_path UTF8String]); NSLog(@"Initializing Python runtime..."); Py_Initialize(); main_script = [ [[NSBundle mainBundle] pathForResource:@"main" ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; if (main_script == NULL) { NSLog(@"Unable to locate jddd main module file."); exit(-1); } // If other modules are using threads, we need to initialize them. PyEval_InitThreads(); @try { // Start the main.py script NSLog(@"Running '%s'...", main_script); FILE* fd = fopen(main_script, "r"); if (fd == NULL) { ret = 1; NSLog(@"Unable to open '%s'; abort.", main_script); } else { ret = PyRun_SimpleFileEx(fd, main_script, 1); fclose(fd); if (ret != 0) { NSLog(@"Application quit abnormally!"); } else { // In a normal iOS application, the following line is what // actually runs the application. It requires that the // Objective-C runtime environment has a class named // "PythonAppDelegate". This project doesn't define // one, because Objective-C bridging isn't something // Python does out of the box. You'll need to use // a library like Rubicon-ObjC [1], Pyobjus [2] or // PyObjC [3] if you want to run an *actual* iOS app. // [1] http://pybee.org/rubicon // [2] http://pyobjus.readthedocs.org/ // [3] https://pythonhosted.org/pyobjc/ UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); } } } @catch (NSException *exception) { NSLog(@"Python runtime error: %@", [exception reason]); } @finally { Py_Finalize(); } NSLog(@"Leaving..."); } exit(ret); return ret; }



在學習Python的過程中,往往因為沒有資料或者沒人指導從而導致自己不想學,可以看我主頁哦 ,配套資料、python、pycharm安裝包可以都有,不管是學習到哪個階段的小伙伴都可以獲取到自己相對應的資料,感謝支持!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM