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
生成的项目的整体目录结构如下所示

3.8 版本 'cpython/initconfig.h' file not found 错误
目前最新的Python版本已经是3.8了,本着使用最新版本的原则,下载了3.8版本,解压后引入工程,
编译项目出现如下错误:

通过错误提示和头部标识,我们发现这个文件不能直接被引用使用,在看下所有的 cpython 目录下文件,除了initconfig.h 文件其他都有 this header file must not be included directly 标识,既然不能直接 included 直接干掉整个 cpython 目录除 initconfig.h 的所有文件。再次编译发现错误如下

在查看python headers 目录下的所有文件,发现还有外层还有一个 pystate.h 文件,里面有一个对 cpython 目录除 pystate.h 引用,但是刚刚已经被我们删了

删除也无法解决问题,说明该方式不对。查看了下issues里面的问题列表,也没有发现该问题和解决方法,既然高版本不行,只能使用3.7了。
3.7 版本
替换项目中的python相关文件,直接编译项目这次更离谱22个错误

查看错误会发现这些报错都是Python目录的 Resource/lib 文件下的文件,直接把该文件目录删除再次运行项目,这次运行成功了。完整的项目截图如下所示

ps记得引入 libz.tdb 和 libsqlite3.tdb 两个模块。
代码尝试 No module named 'encodings' 错误
直接将模版项目中main文件的代码粘贴复制到自己项目中,运行项目这次出现了如下错误

错误是越来越多了,分析下错误提示发现是sqlite3库问题,检查下项目中如下的配置位置,发现是libz.tdb 和 libsqlite3.tdb 两个模块没有被导入,按下图正确导入

再次运行项目,项目运行起来,但是新的错误又出现了

python在初始化的时候失败了没有找到 encodings 模块,想到前面删除的 Resource/lib 文件目录,那么还是我们对模块引入的方式有问题,从网上找了下 iOS 工程中调用Python方法,看到这篇文章有关于Home路径的设置,下载了作者提供的代码,发现可以把该模块制作成 bundle模块引入项目,并修改原代码中关于 python_home 项目终于正确的运行起来了,修改删除无用的代码,并创建测试 main.py 文件,控制台成功打印出日志

完整的 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安装包可以都有,不管是学习到哪个阶段的小伙伴都可以获取到自己相对应的资料,感谢支持!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!