Xamarin Forms如何实现点击邮件链接和电话号码唤起设备对应系统应用
解决方案
第一步:配置必要权限与初始化
首先确保项目已引用Xamarin.Essentials(Xamarin.Forms新版本默认集成),再按平台配置权限:
- Android端
打开Properties/AndroidManifest.xml,添加如下配置适配系统应用查询规则:
<!-- Android 11及以上版本查询系统应用需要 --> <queries> <intent> <action android:name="android.intent.action.DIAL" /> <data android:scheme="tel" /> </intent> <intent> <action android:name="android.intent.action.SENDTO" /> <data android:scheme="mailto" /> </intent> </queries> <!-- 如需直接拨打电话而非打开拨号界面,可额外添加此权限,否则不需要 --> <!-- <uses-permission android:name="android.permission.CALL_PHONE" /> -->
确认Android项目MainActivity.cs的OnCreate方法中已添加Essentials初始化代码:
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); Xamarin.Essentials.Platform.Init(this, savedInstanceState); // 必须添加 // 原有其他初始化代码 }
同时重写权限回调方法转发给Essentials处理:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults) { Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults); base.OnRequestPermissionsResult(requestCode, permissions, grantResults); }
- iOS端无额外权限配置要求,默认支持。
第二步:调整XAML代码
你当前的手势识别器绑定的是Command,而后台实现的是事件方法,直接改为绑定Tapped事件即可,修改后代码如下:
<Label HorizontalTextAlignment="Start" Style="{StaticResource DescriptionLabelStyle}"> <Label.FormattedText> <FormattedString> <Span Text="{x:Static resources:Lang.AccessibilityRepDesc}" /> <Span Text="goteborg@goteborg.se" TextColor="{DynamicResource HyperLink}"> <Span.GestureRecognizers> <TapGestureRecognizer Tapped="EmailClicked" /> </Span.GestureRecognizers> </Span> <Span Text="{helpers:Translate OrCall}" /> <Span Text="031-3650000" TextColor="{DynamicResource HyperLink}"> <Span.GestureRecognizers> <TapGestureRecognizer Tapped="PhoneClicked"/> </Span.GestureRecognizers> </Span> </FormattedString> </Label.FormattedText> </Label>
如果你需要保留Command绑定的MVVM写法,可跳过XAML修改,直接在对应ViewModel或者页面后台定义ICommand属性即可。
第三步:调整后台Code Behind代码
使用Xamarin.Essentials的Launcher API唤起对应系统应用,添加异常捕获避免无对应应用时崩溃:
using Xamarin.Essentials; // 先引入命名空间 private async void EmailClicked(object sender, EventArgs e) { try { // 如需预设邮件主题、内容,可修改为mailto:goteborg@goteborg.se?subject=反馈标题&body=反馈内容 var emailUri = new Uri("mailto:goteborg@goteborg.se"); await Launcher.OpenAsync(emailUri); } catch (Exception ex) { // 无可用邮件应用时的自定义提示逻辑,比如弹Toast提醒用户 Console.WriteLine($"唤起邮件应用失败:{ex.Message}"); } } private async void PhoneClicked(object sender, EventArgs e) { try { var phoneUri = new Uri("tel:031-3650000"); await Launcher.OpenAsync(phoneUri); } catch (Exception ex) { // 无可用电话应用时的自定义提示逻辑 Console.WriteLine($"唤起电话应用失败:{ex.Message}"); } }
如果要保留Command绑定,只需在对应位置定义ICommand即可,示例如下:
public ICommand EmailCommand { get; } public ICommand PhoneCommand { get; } // 页面构造函数或者ViewModel构造函数中初始化 public YourPageName() { InitializeComponent(); EmailCommand = new Command(async () => { // 复制上述EmailClicked方法内的逻辑即可 }); PhoneCommand = new Command(async () => { // 复制上述PhoneClicked方法内的逻辑即可 }); BindingContext = this; // 如用独立ViewModel则赋值为ViewModel实例 }
内容的提问来源于stack exchange,提问作者Jaser
相关产品推荐
相关产品推荐

