Xamarin跨应用数据传输求助:Android与Forms应用收发异常
我来帮你梳理这几个问题的解决方案,都是Xamarin开发中常用的实践方式:
其实Xamarin.Forms的Android宿主本质就是标准的Android应用,咱们可以直接用Android原生的通信机制来实现:
自定义URL Scheme方式
先给你的Xamarin.Forms Android项目配置专属的URL“入口”,在AndroidManifest.xml的MainActivity里加个Intent过滤器:<activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- 这里的scheme和host可以自己定义,比如myapp://data --> <data android:scheme="myapp" android:host="data" /> </intent-filter> </activity>然后在你的Xamarin.Android应用里,通过这个URL启动Forms应用并带参数:
var intent = new Intent(Intent.ActionView, Uri.Parse("myapp://data?username=rafa&message=hello")); StartActivity(intent);接下来在Forms的Android项目里,要把收到的数据传给Forms层。重写MainActivity的
OnNewIntent方法,拿到数据后用MessagingCenter通知Forms页面:protected override void OnNewIntent(Intent intent) { base.OnNewIntent(intent); if (intent.Data != null) { var username = intent.Data.GetQueryParameter("username"); // 用MessagingCenter把数据发去Forms的页面 MessagingCenter.Send<object, string>(this, "DataFromAndroid", username); } }显式Intent传参
如果你知道Forms应用的包名和主Activity的完整类名,也可以直接指定启动目标,不用URL:var intent = new Intent(); // 替换成你的Forms应用的包名和Activity类名 intent.SetComponent(new ComponentName("com.yourcompany.xfdemo", "com.yourcompany.xfdemo.MainActivity")); intent.PutExtra("transfer_data", "这是从Android应用发来的数据"); StartActivity(intent);同样在Forms的Android项目里,在
OnCreate或者OnNewIntent里拿数据:var receivedData = Intent.GetStringExtra("transfer_data"); if (!string.IsNullOrEmpty(receivedData)) { MessagingCenter.Send<object, string>(this, "DataReceived", receivedData); }
因为一个只适配Android,另一个跨平台,咱们分场景来说:
2.1 Android端两个Forms应用互传
和上面的逻辑一样,两边都是Xamarin.Forms的Android宿主,所以直接用URL Scheme或者显式Intent就行。比如发送端按上面的方式发数据,接收端配置好Intent过滤器并处理数据,和第一部分的步骤完全一致。
2.2 跨Android和iOS的通用方案
如果要同时支持Android和iOS,推荐这两种通用方式:
共享文件存储
Android上用外部公共存储(注意权限),iOS上用App Groups共享容器。发送端把数据写成JSON文件存到共享区域,然后通过URL Scheme通知接收端去读取这个文件。
注意:Android 13+需要申请READ_MEDIA_IMAGES/READ_MEDIA_VIDEO等细分权限;iOS要在开发者后台配置App Groups,然后在Info.plist里添加组ID,用NSFileManager访问共享目录。平台专属的本地通信
Android端用LocalBroadcastManager发广播,接收端注册广播接收器;iOS端用App Groups的UserDefaults共享小数据,或者用NSNotificationCenter发本地通知。这种方式适合传递小体量的数据,比如字符串、简单的键值对。
你遇到的打不开其他应用、收不到数据的问题,大概率是这几个常见坑导致的,你可以逐一排查:
权限没配置到位
如果涉及到外部存储,Android 6.0+需要动态申请权限。先在AndroidManifest.xml加权限声明:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />然后在代码里动态申请:
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != Permission.Granted) { ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.ReadExternalStorage }, 1001); }Intent配置出错
- 用URL Scheme的话,要确保接收端的Intent Filter里的scheme、host拼写完全正确,大小写也要一致。
- 用显式Intent的话,目标应用的包名和Activity类名绝对不能错,而且要确认目标应用已经安装在设备上。
- 启动Intent前最好先判断有没有应用能处理,避免崩溃:
if (intent.ResolveActivity(PackageManager) != null) { StartActivity(intent); } else { Toast.MakeText(this, "未找到目标应用", ToastLength.Short).Show(); }
Android 11+的包可见性限制
Android 11及以上版本默认不让应用随便访问其他应用,如果你用显式Intent或者URL Scheme,要在AndroidManifest.xml里加queries标签声明要访问的应用:<queries> <!-- 声明目标应用的包名 --> <package android:name="com.yourcompany.targetapp" /> <!-- 或者声明URL Scheme --> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="myapp" /> </intent> </queries>接收端没处理数据逻辑
如果接收端已经在后台运行,新的Intent会通过OnNewIntent传递,而不是重新走OnCreate,所以要确保接收端的Activity重写了OnNewIntent方法来处理数据,而不是只在OnCreate里写逻辑。
内容的提问来源于stack exchange,提问作者Rafa Vieira

