314 lines
13 KiB
C#
314 lines
13 KiB
C#
using Android.Content;
|
||
using Android.Content.PM;
|
||
using ModelContextProtocol.Server;
|
||
using System.ComponentModel;
|
||
using System.Text.Json;
|
||
|
||
namespace DuoDuo.Platforms.Android.McpTools
|
||
{
|
||
[McpServerToolType]
|
||
public sealed class AndroidApp_Tool
|
||
{
|
||
[McpServerTool, Description("打开指定的Android应用。参数:appName - 应用名称或包名")]
|
||
public static string OpenApp(string appName)
|
||
{
|
||
try
|
||
{
|
||
var context = Platform.CurrentActivity ?? global::Android.App.Application.Context;
|
||
var packageManager = context.PackageManager;
|
||
|
||
// 首先尝试通过包名打开
|
||
if (TryOpenAppByPackageName(context, packageManager, appName))
|
||
{
|
||
return $"成功打开应用: {appName}";
|
||
}
|
||
|
||
// 如果包名方式失败,尝试通过应用名称查找
|
||
var packageName = FindPackageByAppName(packageManager, appName);
|
||
if (!string.IsNullOrEmpty(packageName))
|
||
{
|
||
if (TryOpenAppByPackageName(context, packageManager, packageName))
|
||
{
|
||
return $"成功打开应用: {appName} (包名: {packageName})";
|
||
}
|
||
}
|
||
|
||
return $"未找到应用: {appName}";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return $"打开应用失败: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
[McpServerTool, Description("列出所有已安装的应用")]
|
||
public static string ListInstalledApps()
|
||
{
|
||
try
|
||
{
|
||
var context = Platform.CurrentActivity ?? global::Android.App.Application.Context;
|
||
var packageManager = context.PackageManager;
|
||
var packages = packageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
|
||
|
||
var appList = new List<object>();
|
||
foreach (var package in packages)
|
||
{
|
||
// 只列出有启动器图标的应用(用户应用)
|
||
var launchIntent = packageManager.GetLaunchIntentForPackage(package.PackageName);
|
||
if (launchIntent != null)
|
||
{
|
||
var appName = packageManager.GetApplicationLabel(package)?.ToString() ?? package.PackageName;
|
||
appList.Add(new
|
||
{
|
||
Name = appName,
|
||
PackageName = package.PackageName
|
||
});
|
||
}
|
||
}
|
||
|
||
// 按应用名称排序
|
||
appList = appList.OrderBy(app => ((dynamic)app).Name).ToList();
|
||
|
||
return JsonSerializer.Serialize(new
|
||
{
|
||
Success = true,
|
||
Count = appList.Count,
|
||
Apps = appList
|
||
}, new JsonSerializerOptions { WriteIndented = true });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return JsonSerializer.Serialize(new
|
||
{
|
||
Success = false,
|
||
Error = ex.Message
|
||
});
|
||
}
|
||
}
|
||
|
||
[McpServerTool, Description("搜索应用。参数:keyword - 搜索关键词")]
|
||
public static string SearchApp(string keyword)
|
||
{
|
||
try
|
||
{
|
||
var context = Platform.CurrentActivity ?? global::Android.App.Application.Context;
|
||
var packageManager = context.PackageManager;
|
||
var packages = packageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
|
||
|
||
var searchResults = new List<object>();
|
||
keyword = keyword.ToLower();
|
||
|
||
foreach (var package in packages)
|
||
{
|
||
var launchIntent = packageManager.GetLaunchIntentForPackage(package.PackageName);
|
||
if (launchIntent != null)
|
||
{
|
||
var appName = packageManager.GetApplicationLabel(package)?.ToString() ?? package.PackageName;
|
||
|
||
// 搜索应用名称或包名
|
||
if (appName.ToLower().Contains(keyword) || package.PackageName.ToLower().Contains(keyword))
|
||
{
|
||
searchResults.Add(new
|
||
{
|
||
Name = appName,
|
||
PackageName = package.PackageName
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
return JsonSerializer.Serialize(new
|
||
{
|
||
Success = true,
|
||
Keyword = keyword,
|
||
Count = searchResults.Count,
|
||
Results = searchResults
|
||
}, new JsonSerializerOptions { WriteIndented = true });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return JsonSerializer.Serialize(new
|
||
{
|
||
Success = false,
|
||
Error = ex.Message
|
||
});
|
||
}
|
||
}
|
||
|
||
[McpServerTool, Description("打开系统设置")]
|
||
public static string OpenSettings()
|
||
{
|
||
try
|
||
{
|
||
var context = Platform.CurrentActivity ?? global::Android.App.Application.Context;
|
||
var intent = new Intent(global::Android.Provider.Settings.ActionSettings);
|
||
intent.AddFlags(ActivityFlags.NewTask);
|
||
context.StartActivity(intent);
|
||
return "成功打开系统设置";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return $"打开设置失败: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
[McpServerTool, Description("打开指定的系统设置页面。参数:settingType - 设置类型(wifi/bluetooth/location/app_settings/notification/display/sound/battery)")]
|
||
public static string OpenSpecificSettings(string settingType)
|
||
{
|
||
try
|
||
{
|
||
var context = Platform.CurrentActivity ?? global::Android.App.Application.Context;
|
||
Intent intent;
|
||
|
||
switch (settingType.ToLower())
|
||
{
|
||
case "wifi":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionWifiSettings);
|
||
break;
|
||
case "bluetooth":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionBluetoothSettings);
|
||
break;
|
||
case "location":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionLocationSourceSettings);
|
||
break;
|
||
case "app_settings":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionApplicationDetailsSettings);
|
||
intent.SetData(global::Android.Net.Uri.Parse($"package:{context.PackageName}"));
|
||
break;
|
||
case "notification":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionNotificationListenerSettings);
|
||
break;
|
||
case "display":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionDisplaySettings);
|
||
break;
|
||
case "sound":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionSoundSettings);
|
||
break;
|
||
case "battery":
|
||
intent = new Intent(global::Android.Provider.Settings.ActionBatterySaverSettings);
|
||
break;
|
||
default:
|
||
return $"不支持的设置类型: {settingType}";
|
||
}
|
||
|
||
intent.AddFlags(ActivityFlags.NewTask);
|
||
context.StartActivity(intent);
|
||
return $"成功打开{settingType}设置";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return $"打开设置失败: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
private static bool TryOpenAppByPackageName(Context context, PackageManager packageManager, string packageName)
|
||
{
|
||
try
|
||
{
|
||
var launchIntent = packageManager.GetLaunchIntentForPackage(packageName);
|
||
if (launchIntent != null)
|
||
{
|
||
launchIntent.AddFlags(ActivityFlags.NewTask);
|
||
context.StartActivity(launchIntent);
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
// 忽略异常,返回false
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private static string? FindPackageByAppName(PackageManager packageManager, string appName)
|
||
{
|
||
try
|
||
{
|
||
var packages = packageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
|
||
appName = appName.ToLower();
|
||
|
||
// 首先尝试精确匹配
|
||
foreach (var package in packages)
|
||
{
|
||
var launchIntent = packageManager.GetLaunchIntentForPackage(package.PackageName);
|
||
if (launchIntent != null)
|
||
{
|
||
var installedAppName = packageManager.GetApplicationLabel(package)?.ToString()?.ToLower();
|
||
if (installedAppName == appName)
|
||
{
|
||
return package.PackageName;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果精确匹配失败,尝试模糊匹配
|
||
foreach (var package in packages)
|
||
{
|
||
var launchIntent = packageManager.GetLaunchIntentForPackage(package.PackageName);
|
||
if (launchIntent != null)
|
||
{
|
||
var installedAppName = packageManager.GetApplicationLabel(package)?.ToString()?.ToLower();
|
||
if (installedAppName?.Contains(appName) == true)
|
||
{
|
||
return package.PackageName;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 特殊应用名称映射
|
||
var specialApps = new Dictionary<string, string[]>
|
||
{
|
||
{ "微信", new[] { "com.tencent.mm", "wechat" } },
|
||
{ "支付宝", new[] { "com.eg.android.AlipayGphone", "alipay" } },
|
||
{ "qq", new[] { "com.tencent.mobileqq", "com.tencent.qq" } },
|
||
{ "淘宝", new[] { "com.taobao.taobao", "taobao" } },
|
||
{ "抖音", new[] { "com.ss.android.ugc.aweme", "douyin", "tiktok" } },
|
||
{ "百度", new[] { "com.baidu.searchbox", "baidu" } },
|
||
{ "高德地图", new[] { "com.autonavi.minimap", "amap" } },
|
||
{ "美团", new[] { "com.sankuai.meituan", "meituan" } },
|
||
{ "京东", new[] { "com.jingdong.app.mall", "jd" } },
|
||
{ "网易云音乐", new[] { "com.netease.cloudmusic", "cloudmusic" } },
|
||
{ "bilibili", new[] { "tv.danmaku.bili", "com.bilibili.app.in" } },
|
||
{ "知乎", new[] { "com.zhihu.android", "zhihu" } },
|
||
{ "小红书", new[] { "com.xingin.xhs", "xiaohongshu" } },
|
||
{ "携程", new[] { "ctrip.android.view", "ctrip" } },
|
||
{ "饿了么", new[] { "me.ele", "eleme" } }
|
||
};
|
||
|
||
// 检查特殊应用映射
|
||
foreach (var kvp in specialApps)
|
||
{
|
||
if (appName.Contains(kvp.Key) || kvp.Value.Any(v => appName.Contains(v)))
|
||
{
|
||
foreach (var possiblePackage in kvp.Value)
|
||
{
|
||
if (IsPackageInstalled(packageManager, possiblePackage))
|
||
{
|
||
return possiblePackage;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
// 忽略异常
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
private static bool IsPackageInstalled(PackageManager packageManager, string packageName)
|
||
{
|
||
try
|
||
{
|
||
packageManager.GetPackageInfo(packageName, PackageInfoFlags.MatchAll);
|
||
return true;
|
||
}
|
||
catch (PackageManager.NameNotFoundException)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
} |