iOS 項目中使用 Python

iOS 項目中如何使用 Python

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

對于包體積大小我們可以從資源文件和編碼來控制啄栓,如何減少項目編譯文件的大小娄帖,只能從代碼層面去進行一些優(yōu)化,如規(guī)范代碼昙楚,合理的使用組合近速、繼承等設計模式。對于資源文件堪旧,如圖片我們可以進行壓縮后在集成削葱。下面就是如何利用python對項目中的使用的圖片進行檢測并實現(xiàn)在線壓縮、上傳等功能淳梦。

正確引入 Python

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

模版項目的安裝

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

step1 執(zhí)行 $ pip install cookiecutter 安裝 cookiecutter 插件

step2 執(zhí)行 $ 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版本闲先,解壓后引入工程,
編譯項目出現(xiàn)如下錯誤:

1.png

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

2.png

在查看python headers 目錄下的所有文件,發(fā)現(xiàn)還有外層還有一個 pystate.h 文件酣倾,里面有一個對 cpython 目錄除 pystate.h 引用舵揭,但是剛剛已經被我們刪了

3.png

刪除也無法解決問題,說明該方式不對躁锡。查看了下issues里面的問題列表午绳,也沒有發(fā)現(xiàn)該問題和解決方法,既然高版本不行映之,只能使用3.7了拦焚。

3.7 版本

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

4.png

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

5.png

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

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

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

6.png

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

7.png

再次運行項目能岩,項目運行起來寞宫,但是新的錯誤又出現(xiàn)了

8.png

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

9.png

完整的 main.m 代碼

#import <UIKit/UIKit.h>
#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-Apple-support

iOS 工程中調用Python方法

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末近忙,一起剝皮案震驚了整個濱河市竭业,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌及舍,老刑警劉巖未辆,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锯玛,居然都是意外死亡咐柜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門更振,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炕桨,“玉大人,你說我怎么就攤上這事肯腕∠坠” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵实撒,是天一觀的道長姊途。 經常有香客問我涉瘾,道長,這世上最難降的妖魔是什么捷兰? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任立叛,我火速辦了婚禮,結果婚禮上贡茅,老公的妹妹穿的比我還像新娘秘蛇。我一直安慰自己,他們只是感情好顶考,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布赁还。 她就那樣靜靜地躺著,像睡著了一般驹沿。 火紅的嫁衣襯著肌膚如雪艘策。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天渊季,我揣著相機與錄音朋蔫,去河邊找鬼。 笑死却汉,一個胖子當著我的面吹牛驯妄,可吹牛的內容都是我干的。 我是一名探鬼主播病涨,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼富玷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了既穆?” 一聲冷哼從身側響起赎懦,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幻工,沒想到半個月后励两,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡囊颅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年当悔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踢代。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡盲憎,死狀恐怖,靈堂內的尸體忽然破棺而出胳挎,到底是詐尸還是另有隱情饼疙,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布慕爬,位于F島的核電站窑眯,受9級特大地震影響屏积,放射性物質發(fā)生泄漏。R本人自食惡果不足惜磅甩,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一炊林、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卷要,春花似錦渣聚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彪标,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掷豺,已是汗流浹背捞烟。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留当船,地道東北人题画。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像德频,于是被迫代替她去往敵國和親苍息。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354