feat: 新增 3 个 Operit 安卓 API 示例脚本 (全链路验证通过)
- system_info.py: Environment 存储目录 + Build 构建信息 + Log 日志 + platform (转译层核心 API) - file_manager.py: Environment 外部存储 + 列目录/写文本/读文本 (真实文件系统操作) - intent_builder.py: Intent ACTION_VIEW/ACTION_SEND + Uri 解析 + putExtra (组件通信) - 全链路验证: list 识别 4 脚本 7 工具; run 全部 success (含 Log I/W 输出) - 配套修复 android_pyapi (Intent.EXTRA_TEXT 挂载, 已推送 Gitee e2f78f3)
This commit is contained in:
1 parent
a71daf32c6
commit
f7f7033e57
3 files changed
+268
No files matched your search
@@ -0,0 +1,114 @@
|
||||
# METADATA
|
||||
# {
|
||||
# "name": "file_manager",
|
||||
# "display_name": {
|
||||
# "zh": "Android 文件管理器",
|
||||
# "en": "Android File Manager"
|
||||
# },
|
||||
# "description": {
|
||||
# "zh": "通过 Environment 获取外部存储目录,支持列目录、读文本、写文本(真实文件系统操作)。",
|
||||
# "en": "Use Environment to get external storage dir; list dir, read/write text files on real filesystem."
|
||||
# },
|
||||
# "category": "Files",
|
||||
# "tools": [
|
||||
# {
|
||||
# "name": "list_dir",
|
||||
# "description": {
|
||||
# "zh": "列出目录内容",
|
||||
# "en": "List directory contents"
|
||||
# },
|
||||
# "parameters": [
|
||||
# { "name": "path", "description": { "zh": "目录路径(默认外部存储根)", "en": "Dir path (default external storage root)" }, "type": "string", "required": false }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "name": "write_text",
|
||||
# "description": {
|
||||
# "zh": "写入文本文件",
|
||||
# "en": "Write text file"
|
||||
# },
|
||||
# "parameters": [
|
||||
# { "name": "file_path", "description": { "zh": "文件绝对路径", "en": "Absolute file path" }, "type": "string", "required": true },
|
||||
# { "name": "content", "description": { "zh": "文本内容", "en": "Text content" }, "type": "string", "required": true }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "name": "read_text",
|
||||
# "description": {
|
||||
# "zh": "读取文本文件",
|
||||
# "en": "Read text file"
|
||||
# },
|
||||
# "parameters": [
|
||||
# { "name": "file_path", "description": { "zh": "文件绝对路径", "en": "Absolute file path" }, "type": "string", "required": true }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
|
||||
TAG = "FileManager"
|
||||
|
||||
|
||||
def _resolve(path):
|
||||
"""解析路径:默认落到外部存储根"""
|
||||
if path and path.strip():
|
||||
return os.path.abspath(path.strip())
|
||||
return Environment.getExternalStorageDirectory()
|
||||
|
||||
|
||||
async def list_dir(params):
|
||||
path = _resolve((params or {}).get("path", ""))
|
||||
if not os.path.isdir(path):
|
||||
raise Exception(f"目录不存在: {path}")
|
||||
entries = []
|
||||
for name in sorted(os.listdir(path)):
|
||||
full = os.path.join(path, name)
|
||||
entries.append({
|
||||
"name": name,
|
||||
"type": "dir" if os.path.isdir(full) else "file",
|
||||
"size": os.path.getsize(full) if os.path.isfile(full) else None,
|
||||
})
|
||||
Log.i(TAG, f"列出 {path}: {len(entries)} 项")
|
||||
result = {"path": path, "count": len(entries), "entries": entries[:100]}
|
||||
complete({"success": True, "message": f"已列出 {len(entries)} 项", "data": result})
|
||||
return result
|
||||
|
||||
|
||||
async def write_text(params):
|
||||
file_path = os.path.abspath((params or {}).get("file_path", ""))
|
||||
content = (params or {}).get("content", "")
|
||||
if not file_path:
|
||||
raise Exception("file_path 不能为空")
|
||||
os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
|
||||
with open(file_path, "w", encoding="utf-8") as fh:
|
||||
fh.write(content)
|
||||
size = os.path.getsize(file_path)
|
||||
Log.w(TAG, f"已写入 {file_path} ({size} 字节)")
|
||||
result = {"file_path": file_path, "bytes": size}
|
||||
complete({"success": True, "message": f"写入成功 ({size} 字节)", "data": result})
|
||||
return result
|
||||
|
||||
|
||||
async def read_text(params):
|
||||
file_path = os.path.abspath((params or {}).get("file_path", ""))
|
||||
if not file_path:
|
||||
raise Exception("file_path 不能为空")
|
||||
if not os.path.isfile(file_path):
|
||||
raise Exception(f"文件不存在: {file_path}")
|
||||
with open(file_path, "r", encoding="utf-8", errors="replace") as fh:
|
||||
content = fh.read()
|
||||
result = {"file_path": file_path, "bytes": len(content.encode("utf-8")), "content": content[:20000]}
|
||||
complete({"success": True, "message": f"读取成功 ({len(content)} 字符)", "data": result})
|
||||
return result
|
||||
|
||||
|
||||
async def _dispatch(params):
|
||||
action = (params or {}).get("action", "list_dir")
|
||||
func = {"list_dir": list_dir, "write_text": write_text, "read_text": read_text}.get(action)
|
||||
if not func:
|
||||
raise Exception(f"未知操作: {action}(支持 list_dir/write_text/read_text)")
|
||||
return await func(params)
|
||||
|
||||
|
||||
exports.list_dir = list_dir
|
||||
exports.write_text = write_text
|
||||
exports.read_text = read_text
|
||||
@@ -0,0 +1,76 @@
|
||||
# METADATA
|
||||
# {
|
||||
# "name": "intent_builder",
|
||||
# "display_name": {
|
||||
# "zh": "Intent 意图构建器",
|
||||
# "en": "Intent Builder"
|
||||
# },
|
||||
# "description": {
|
||||
# "zh": "用 android.content.Intent 构建意图:ACTION_VIEW 打开 URL、ACTION_SEND 分享文本,解析 Uri,并用 Log 输出。",
|
||||
# "en": "Build intents with android.content.Intent: ACTION_VIEW for URLs, ACTION_SEND for sharing text, parse Uri, log via Log."
|
||||
# },
|
||||
# "category": "System",
|
||||
# "tools": [
|
||||
# {
|
||||
# "name": "build_view_intent",
|
||||
# "description": {
|
||||
# "zh": "构建 ACTION_VIEW 意图(打开 URL)",
|
||||
# "en": "Build ACTION_VIEW intent (open URL)"
|
||||
# },
|
||||
# "parameters": [
|
||||
# { "name": "url", "description": { "zh": "要打开的网址", "en": "URL to open" }, "type": "string", "required": true }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "name": "build_share_intent",
|
||||
# "description": {
|
||||
# "zh": "构建 ACTION_SEND 分享意图",
|
||||
# "en": "Build ACTION_SEND share intent"
|
||||
# },
|
||||
# "parameters": [
|
||||
# { "name": "text", "description": { "zh": "分享的文本", "en": "Text to share" }, "type": "string", "required": true }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
|
||||
TAG = "IntentBuilder"
|
||||
|
||||
|
||||
async def build_view_intent(params):
|
||||
url = (params or {}).get("url", "")
|
||||
if not url:
|
||||
raise Exception("url 不能为空")
|
||||
intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setData(Uri.parse(url))
|
||||
Log.i(TAG, f"ACTION_VIEW -> {url}")
|
||||
result = {
|
||||
"action": intent.getAction(),
|
||||
"data": intent.getData(),
|
||||
"flags": intent.getFlags(),
|
||||
"resolved": intent.toString(),
|
||||
}
|
||||
complete({"success": True, "message": "意图构建成功(桌面环境不实际拉起)", "data": result})
|
||||
return result
|
||||
|
||||
|
||||
async def build_share_intent(params):
|
||||
text = (params or {}).get("text", "")
|
||||
if not text:
|
||||
raise Exception("text 不能为空")
|
||||
intent = Intent(Intent.ACTION_SEND)
|
||||
intent.setType("text/plain")
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text)
|
||||
Log.i(TAG, f"ACTION_SEND: {text[:40]}")
|
||||
result = {
|
||||
"action": intent.getAction(),
|
||||
"type": intent.getType(),
|
||||
"extras": intent.getExtras(),
|
||||
"resolved": intent.toString(),
|
||||
}
|
||||
complete({"success": True, "message": "分享意图构建成功", "data": result})
|
||||
return result
|
||||
|
||||
|
||||
exports.build_view_intent = build_view_intent
|
||||
exports.build_share_intent = build_share_intent
|
||||
@@ -0,0 +1,78 @@
|
||||
# METADATA
|
||||
# {
|
||||
# "name": "system_info",
|
||||
# "display_name": {
|
||||
# "zh": "系统信息查看器",
|
||||
# "en": "System Info Viewer"
|
||||
# },
|
||||
# "description": {
|
||||
# "zh": "通过 Android API 转译层获取系统信息:存储目录、构建信息、平台环境,并用 Log 输出日志。",
|
||||
# "en": "Get system info via Android API translation layer: storage dirs, build info, platform. Log via android.util.Log."
|
||||
# },
|
||||
# "category": "System",
|
||||
# "tools": [
|
||||
# {
|
||||
# "name": "get_info",
|
||||
# "description": {
|
||||
# "zh": "获取系统信息",
|
||||
# "en": "Get system info"
|
||||
# },
|
||||
# "parameters": []
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
|
||||
import platform
|
||||
import sys
|
||||
|
||||
TAG = "SystemInfo"
|
||||
|
||||
|
||||
def getErrorMessage(error):
|
||||
return str(error) if error else "unknown"
|
||||
|
||||
|
||||
def getErrorStack(error):
|
||||
return traceback.format_exc()
|
||||
|
||||
|
||||
async def wrap(func, params):
|
||||
try:
|
||||
result = await func(params)
|
||||
complete({"success": True, "message": "操作成功", "data": result})
|
||||
except Exception as error:
|
||||
console.error(f"Error: {getErrorMessage(error)}")
|
||||
complete({"success": False, "message": getErrorMessage(error), "error_stack": getErrorStack(error)})
|
||||
|
||||
|
||||
async def get_info(params):
|
||||
"""通过 Android API 转译层采集系统信息"""
|
||||
try:
|
||||
info = {
|
||||
"storage_external": Environment.getExternalStorageDirectory(),
|
||||
"storage_data": Environment.getDataDirectory(),
|
||||
"storage_root": Environment.getRootDirectory(),
|
||||
"storage_public_pictures": Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
|
||||
"build_brand": getattr(Build, "BRAND", "unknown"),
|
||||
"build_model": getattr(Build, "MODEL", "unknown"),
|
||||
"build_version": getattr(Build, "VERSION", {}).get("RELEASE", "unknown") if isinstance(getattr(Build, "VERSION", {}), dict) else "unknown",
|
||||
"os_name": os.name,
|
||||
"sys_platform": sys.platform,
|
||||
"python_version": platform.python_version(),
|
||||
"python_platform": platform.platform(),
|
||||
"sdcard_mounted": Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED,
|
||||
}
|
||||
Log.i(TAG, f"采集完成: external={info['storage_external']}")
|
||||
complete({"success": True, "message": "系统信息采集完成", "data": info})
|
||||
return info
|
||||
except Exception as error:
|
||||
console.error(f"{TAG} 错误: {getErrorMessage(error)}")
|
||||
complete({"success": False, "message": f"采集失败: {getErrorMessage(error)}", "error_stack": getErrorStack(error)})
|
||||
raise
|
||||
|
||||
|
||||
async def get_info_wrapper(params):
|
||||
await wrap(get_info, params)
|
||||
|
||||
|
||||
exports.get_info = get_info_wrapper
|
||||
Reference in new issue
Block a user