Python学习笔记--BeeWare跨平台打包方案2


首先贴上官方的地址: BeeWare 教程
其中的安装和初始化过程在上一片有描述,这张介绍一些基础使用:

1. 多文件开发支持

通常一个工程下我们通常会分为多个 app进行开发,例如如下目录:
在这里插入图片描述
如果我们按照一般的引入方法:
会出现找不到模块错误,这里看下官方的解释issues
也就是以下几步骤:

  1. 在目录下创建__init__.py
  2. 导入方式:from logfileprocess.tools.webrtc_log import extract_objc_lines_from_logs,然后就可以按照正常的方式使用了

2. java和Python交互

java调用python

BeeWare使用的是chaquopy和Java进行交互(我还是认为Jep - Java Embedded Python的交互方式比较好,当然BeeWare选择这个,那就用这个也是可以),其文档地址,;初始化完BeeWare后就会自动在Python环境和Java环境配置好chaquopy相关的配置,这里我们直接看一个简单的调用:

  1. 在app.py中新增如下代码:
def hello_python(str):
    print(u"Hello, Python({})!!!!!!".format(str))

2.在Java的MainActivity中新增

  py.getModule("logfileprocess.app").callAttr(
        "hello_python","sdcard/0/logfileprocess"
    );

关于chaquopy的Python对象创建,这里在后面分析源码的时候说,具体的可以看原文实现;
然后在命令行执行:

briefcase build android -r

在实际测试的时候如果不加-r,Python修改的代码不会同步;
接着执行

briefcase run android 

在控制台就是输出:
在这里插入图片描述
这里看到我们从Java传递的参数在Python中输出了

python调用java

这里直接使用MainActivity类做示范:
现在类中增加方法:

 public static void onPthonCallback(String msg){
        Log.d("MainActivity 这是来及Java--》",msg);
    }

python中调用:
首先引入# 调用 Java 的 Android API 示例

from java import jclass

调用Java方法:

# 获取 Java 类
MyJavaClass = jclass('org.beeware.android.MainActivity')

# 创建类的实例
my_java_object = MyJavaClass()

# 调用 Java 方法
my_java_object.onPthonCallback("John")

输出结果:
在这里插入图片描述

其他类

这里使用自定义的Java类,然后在Python中调用,Java类的定义如下:

package org.beeware.android;

public class ProcessLogFile {
    static private ProcessLogFile instance;
    // 定义一个接口用于回调
    public interface OnPythonCallbackListener {
        void onPythonCallback(String msg);
    }

    // 接口的实例
    private final OnPythonCallbackListener callbackListener;

    // 构造方法,接受接口实现的对象
    public ProcessLogFile(OnPythonCallbackListener listener) {
        instance = this;
        this.callbackListener = listener;
    }
    public void onPthonCallback(String msg){
        // 确保 UI 更新在主线程中进行
        // 调用回调方法将消息传递给 MainActivity
        if (callbackListener != null) {
            callbackListener.onPythonCallback(msg);
        }
    }
    public static ProcessLogFile getInstance(){
        return instance;
    }
}

这里使用static private ProcessLogFile instance;的方式,是为了在Python中不用再new一个对象,和Java中的对象保持一致;
其中的 public void onPthonCallback(String msg)是Python中调用,只有单例模式,才能保持一个对象,从而在设置回调监听的类里面才能拿到ProcessLogFile回调接口的数据;
Python中调用Java接口:

def isAndroid():
    if plt == "Windows":
        # print("Your system is Windows")
        return False
        # do x y z
    elif plt == "Linux":
        print("Your system is Linux")
        if "ANDROID_BOOTLOGO" in environ:
            # print("====================>Running on Android")
            return True
        else:
            # print("Not Android OS")
            return False
        # do x y z
    elif plt == "Darwin":
        # print("Your system is MacOS")
        return False
        # do x y z
    else:
        # print("Unidentified system")
        return False
def process_log_queue_(message):
    if isAndroid():
        # 获取Java对应的类
        ProcessLogFile = jclass("org.beeware.android.ProcessLogFile")
        # 调用静态方法获取 processLogFile 实例对象
        my_java_object = ProcessLogFile.getInstance()
        # 创建类的实例 Java中使用单例的方式 就是避免这里又要new一个对象
        # my_java_object = MyJavaClass()
        print("------>" + message)

        # 调用 Java 方法
        my_java_object.onPthonCallback(message)
    else:
        # global log_messages
        # log_messages.append(msg)  # 将消息添加到日志列表
        update_log_view(message)  # 更新日志视图
        print("------>" + message)

Python中主线程调用

这里使用定时器定时从队列中取出消息转发的机制;

  1. 定义queue
# 创建一个线程安全的队列,用于在后台线程与主线程间传递日志消息
log_queue = queue.Queue()
  1. 将消息放入队列的方法
def send_msg_toJava(msg):
    log_queue.put(msg)
  1. 定义定时器和执行方法
# 定时器,每隔一段时间执行一次
def start_processing_log_queue():
    loop = asyncio.get_event_loop()
    loop.create_task(process_log_queue())  # 启动日志处理任务

async def process_log_queue():
    while True:
        # 如果队列不为空,获取并处理消息
        if not log_queue.empty():
            message = log_queue.get()
            if message:
                process_log_queue_(message)  # 更新日志视图
        await asyncio.sleep(0.03)  # 每 30ms 检查一次队列

最后的process_log_queue_方法中调用Java的方法就基本能保证是在主线程调用

补充一种简单调用

使用 add_background_task,确保 process_log_queue_ 在主线程中调用

   toga.App.app.add_background_task(lambda app: process_log_queue_(message))

主要命令

  1. MacOS等桌面平台可以直接使用briefcase dev运行,打包使用:
briefcase package macOS

或者使用

 briefcase build macos xcode

这个会生成一个xcode工程,双击打开后就可以使用xcode打包

  1. 移动端,Android为例子如下:
  • 编译使用briefcase build android -rbriefcase build android,这两个的差别实际测试中,不加-r不会编译Python的修改,只会编译Android的修改代码;
  • 运行执行briefcase run android,然后选择执行真机还是模拟器即可;也可以直接使用adb命令安装build目录下的apk

macos上其他问题

使用pyenv管理Python版本

由于briefcase是Python3的,所以为了便于管理Python版本这里使用pytnv安装Python3:
pyenv在 macOS 11 (Apple Silicon) 上安装
在 macOS 上安装有两种方法pyenv:

  1. 通过Homebrew:这是最快的方法。但是,无法pyenvmacOS 11(Apple Silicon)上安装;
  2. 直接编译 Git checkout:pyenv团队已在README中详细记录了安装过程。但是,当我按照步骤一步步操作并应用于我的新 macOS 11 (M1) 时,最终没有起作用。经过几个小时的调整,以下是我设法使其与 Git check out 安装配合使用的方法。
  • 将 repo克隆pyenv到你的主文件夹中:
   git clone https://github.com/pyenv/pyenv.git ~/.pyenv 
   cd ~/.pyenv && src/configure && make -C src
  • 编辑.zshrc并在文件底部添加以下几行(macOS 11 自带 zsh 作为默认 shell)
export PYENV_ROOT="$HOME/.pyenv" 
export PATH="$PYENV_ROOT/bin:$PATH" 
eval "$(pyenv init --path)" 
eval "$(pyenv init -)"
  • 退出终端并重新打开。现在pyenv已经安装成功。使用方式如下:

    • 查看 pyenv 已经管理了哪些 python 版本
    pyenv versions
    
    • 使用pyenv安装指定的Python版本
    pyenv install -v 3.12.3 
    pyenv install -v 2.7.13 
    
    • 把Python切换到指定版本
    pyenv global 3.12.3
    
    • 查看系统当前python版本
    python
    

    输出

Python 3.8.9 (default, Jun 23 2021, 14:45:36)
* 查看pyenv当前支持哪些Python版本

```bash
pyenv install --list 
```

1. urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the ‘ssl’ module is compiled with 'OpenSSL 1.0.2r

如果遇到这个问题,需要重新执行以下步骤:

  1. 升级openssl,执行
brew reinstall openssl@1.1

然后将这个添加到.zshrc环境中:

echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc
source  ~/.zshrc

接着执行:

  export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
  export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"

上面三个是将连接的库指向OpenSSL1.1
2. 安装低版本的

pip install urllib3==1.26.6

如果还报错重装Python3的:

pip3 install urllib3==1.26.6

2. 如果遇到pkg_resources.VersionConflict: (wheel 0.33.0 (/usr/local/lib/python3.7/site-packages), Requirement.parse(‘wheel>=0.34’))

执行:

pip3 install --upgrade wheel

3. 提示缺失Model

执行:

pip3 install toga
pip3 install matplotlib
pip3 install --pre toga
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简简单单lym

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值