马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 blurred 于 2026-2-10 09:04 编辑
前言:
1.此方法由"我"单独提出,实现,测试
2.本方案在Ren'py-8.3.7能够实现效果,如果使用,请注意引擎版本
3.涉及到修改引擎的代码,所以请在事前把引擎目录下的rapt相关文件备份
3.学习操作门槛:需要一定的java小基础以及了解Android应用的相关特性
(包括但不限于一些基础的apk知识,apk的文件结构以及其rapt各个文件作用和内容)
4.你使用了这个方案来调用相册权限,可以在游戏名单标上“浅唱”,不标也没关系
本帖参考:
一个在Ren'py中调用手机通知和(小米特有)卸载弹窗方案 - 经验教程 - RenPy中文空间
一个Renpy打包安卓游戏的不调用安全输入法的解决方案 - 经验教程 - RenPy中文空间
一个Renpy打包安卓游戏的不调用安全输入法的解决方案 - 经验教程 - RenPy中文空间
一个Renpy安卓打包游戏通过安卓平台审核方案 - 经验教程 - RenPy中文空间
效果预览:
压缩包:(懒得看帖子可以一键解压即可食用)(内置食用教程和餐具)
https://www.renpy.cn/forum.php?mod=attachment&aid=MTY5NHxiNjI0OWM3OHwxNzcyMDE2NzE3fDB8
方法思路以及部分代码解释:
在renpy中,我们需要实现安卓扩展功能都一定要改rapt,所以按照惯例,我们打开了PythonSDLActivity.java并且敏锐地发现,关于外部文件引用的代码——一行没有
所以我们需要自己定义一个用于uri转化的方法,这里特别感谢龙叔(@Aaron栩生阿龙 )给出的参考代码
PythonSDLActivity.java
首先导入需要的模块
[RenPy] 纯文本查看 复制代码 import android.content.Intent;
import android.net.Uri;
import android.database.Cursor;
import android.provider.MediaStore;
import java.io.InputStream;
import java.io.OutputStream;
然后我们写几个方法,分别用于:使用请求码(2024)打开相册,Renpy中调用获取图片路径,图片路径和uri转化
打开相册
[RenPy] 纯文本查看 复制代码 // 定义请求码
private static final int PICK_IMAGE_REQUEST = 2024;
// 保存选中的图片路径
public static String lastPickedImagePath = "";
// 供 Ren'Py 调用:打开相册
public void openSystemAlbum() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/Q_C_pick/*");
Log.i("openSystemAlbum", "Opening system album.");
startActivityForResult(intent, PICK_IMAGE_REQUEST);
}
调用路径
[RenPy] 纯文本查看 复制代码 public String getPickedPath() {
String path = lastPickedImagePath;
lastPickedImagePath = "";
Log.i("openSystemAlbum", "getPickedPath returning: " + path);
return path;
}
图片路径和uri转化
[RenPy] 纯文本查看 复制代码 private String getRealPathFromURI(Uri contentUri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
if(cursor != null) {
if(cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
}
Log.i("openSystemAlbum", "Real path from URI: " + res);
return res;
}
关于uri转文件路径,这部分修改原有的onActivityResult就行
[RenPy] 纯文本查看 复制代码 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (mStore != null && mStore.onActivityResult(requestCode, resultCode, resultData)) {
return;
}
// 修改 onActivityResult
super.onActivityResult(requestCode, resultCode, resultData);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && resultData != null && resultData.getData() != null) {
Uri uri = resultData.getData();
// 将 Uri 转换为真实文件路径
lastPickedImagePath = getRealPathFromURI(uri);
Log.i("openSystemAlbum", "Selected image path: " + lastPickedImagePath);
}
if (mStore != null && mStore.onActivityResult(requestCode, resultCode, resultData)) {
return;
}
//
Log.v("python", "onActivityResult(" + requestCode + ", " + resultCode + ", " + resultData.toString() + ")");
mActivityResultRequestCode = requestCode;
mActivityResultResultCode = resultCode;
mActivityResultResultData = resultData;
super.onActivityResult(requestCode, resultCode, resultData);
}
至此,关于调用的java基层就写完了,剩下的就是调用java中的接口,用rpy中的python函数调用接口即可,我们先写一个类用于管理
在此之前要先导入模块
[Python] 纯文本查看 复制代码 # 导入jnius
if renpy.android:
from jnius import autoclass
import os
import shutil
# 标记是否为安卓环境
is_android = True
else:
is_android = False
相册类
[Python] 纯文本查看 复制代码 class AlbumManager(object):
def __init__(self):
if not is_android:
renpy.notify("当前不是 Android 平台,无法调用相册")
self.activity = None
return
try:
self.PythonSDLActivity = autoclass('org.renpy.android.PythonSDLActivity')
self.activity = self.PythonSDLActivity.mActivity
self.last_saved_filename = ""
except Exception as e:
renpy.notify(f"初始化 Java 类失败: {e}")
self.activity = None
def open_gallery(self):
# 调用java中的openSystemAlbum
self.activity.openSystemAlbum()
def fetch_and_copy_image(self):
# 调用java中的getPickedPath
source_path = self.activity.getPickedPath()
renpy.notify(f"Picked image path: {source_path}")
# 这个notify是调试用的,可以删除
if not source_path:
return None
target_dir = os.path.join(config.gamedir, "images/Q_C_pick")
# 定义图片路径,这里必须和下面图片变量定义一样
if not os.path.exists(target_dir):
os.makedirs(target_dir)
original_filename = os.path.basename(source_path)
dest_filename = "picked_" + original_filename
# 在获取的图片名前加上picked_
target_path = os.path.join(target_dir, dest_filename)
try:
shutil.copy(source_path, target_path)
self.last_saved_filename = dest_filename
renpy.notify(f"Image copied to: {target_path}")
# 这个notify是调试用的,可以删除
return dest_filename
except Exception as e:
renpy.notify("Copy Error: " + str(e))
# 这个notify是调试用的,可以删除
return None
def get_image_name(self):
return self.last_saved_filename
剩下的就是使用,这里给出一个使用案例
[RenPy] 纯文本查看 复制代码 # 首先先实例化Album
# 然后调用open_gallery()打开相册
# 之后调用fetch_and_copy_image()获取所选图片并复制到游戏目录,返回图片文件名
# 获取图片要像picked_img = "images/Q_C_pick/" + img_name,前面的"images/Q_C_pick/"是必须的,不然会找不到图片
# 然后这里定义了一个变量用于临时储存获取的图片
# 在使用前,你需要使用request_permission获取权限,不然会失败
# 这里给出一个使用并且用show语句展示
label album_test:
"准备调用相册..."
python:
# 授权权限,你可以把这一部分移动到别的地方,但是需要在调用相册前申请权限
for pess in build.android_permissions:
renpy.request_permission(pess)
#
album = AlbumManager()
album.open_gallery()
"选照片"
python:
img_name = album.fetch_and_copy_image()
if img_name:
$ picked_img = "images/Q_C_pick/" + img_name
"成功:[img_name]"
show expression picked_img at truecenter
"[img_name]"
jump album_test
至此功能实现完毕,本身这个方案的原理是复制多张玩家的照片到游戏的应用私有目录,然后读取私有目录下的图片来显示,理论可以实现更多效果,代价就是选择的图片多了会导致占用空间变大,这个调用可以结合画廊或者其他储存功能,例如保存玩家选择的图片名字,这样后续可以再次调用玩家选择过的图片,而不只是当前选择的图片,这一部分我不展开
闲言:
其实这个功能前前后后做了许久,一开始是想着直接访问外部文件,结果总是失败,后面转化思路改为复制文件就成功了,目前这个方案还有许多欠缺
比如单次只能选择一张图片,选择图片多了会导致游戏占用空间很大,只能说我太菜不会解决了(
视频版本教程:
|