如何在Xamarin.Forms中通过DependencyService实现无拨号界面直接通话?
解决Xamarin.Forms Android端直接通话的"Unable to add window - token null"异常
看起来你碰到的问题核心是Android上下文使用不当,加上可能缺少必要的权限校验。咱们一步步来解决:
1. 先搞定通话权限(关键前提)
Android 6.0(API 23)及以上需要动态申请CALL_PHONE权限,光在Manifest里加还不够。
- 首先在
AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.CALL_PHONE" />
- 然后在调用通话前,先检查并申请权限:
在Android端的实现类中加入权限校验逻辑:
// 在MakeQuickCall方法开头添加 if (ContextCompat.CheckSelfPermission(MainActivity.Instance, Manifest.Permission.CallPhone) != Permission.Granted) { ActivityCompat.RequestPermissions(MainActivity.Instance, new[] { Manifest.Permission.CallPhone }, 100); return; }
2. 修复上下文问题,避免token null异常
你用MainActivity静态实例的思路是对的,但要确保实例在生命周期中正确维护,并且必须用Activity上下文启动Intent,不能用Application上下文。
修正MainActivity的静态实例维护
public class MainActivity : FormsAppCompatActivity { internal static MainActivity Instance { get; private set; } protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); Instance = this; // 初始化实例 Xamarin.Essentials.Platform.Init(this, savedInstanceState); global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App()); } // 销毁时置空实例,避免内存泄漏 protected override void OnDestroy() { base.OnDestroy(); Instance = null; } // 处理权限申请结果 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); } }
修正Android端的通话实现类
[assembly: Dependency(typeof(PhoneCall_Droid))] namespace MakeCall.Droid { public class PhoneCall_Droid : IPhoneCall { public void MakeQuickCall(string PhoneNumber) { try { var activity = MainActivity.Instance; if (activity == null) { throw new Exception("当前没有可用的Activity上下文"); } // 检查权限 if (ContextCompat.CheckSelfPermission(activity, Manifest.Permission.CallPhone) != Permission.Granted) { ActivityCompat.RequestPermissions(activity, new[] { Manifest.Permission.CallPhone }, 100); return; } // 构建通话Intent并启动 var uri = Android.Net.Uri.Parse($"tel:{PhoneNumber}"); var intent = new Intent(Intent.ActionCall, uri); intent.AddFlags(ActivityFlags.NewTask); // 确保Intent在当前栈中启动 activity.StartActivity(intent); } catch (Exception ex) { // 用Activity上下文弹窗,避免token null问题 new AlertDialog.Builder(MainActivity.Instance) .SetPositiveButton("OK", (sender, args) => { }) .SetMessage(ex.ToString()) .SetTitle("Android Exception") .Show(); } } } }
3. 为什么之前的方案不行?
Forms.Context在新版本Xamarin.Forms中已被标记为过时,它返回的是Application上下文,而Application上下文无法启动需要依附Activity的Intent(这就是token null异常的根源)。- 你之前用Application上下文弹AlertDialog也会触发同样的异常,因为弹窗必须依附于一个活跃的Activity。
额外提示:用Xamarin.Essentials简化实现
其实Xamarin.Essentials已经内置了通话功能,如果你不需要完全跳过拨号界面,可以直接用它来减少代码量:
// 共享库中直接调用 try { if (Xamarin.Essentials.PhoneDialer.IsSupported) { await Xamarin.Essentials.PhoneDialer.OpenAsync("+xxxxxxxxx"); } } catch (Exception ex) { await DisplayAlert("Alert!!!", ex.Message, "ok"); }
内容的提问来源于stack exchange,提问作者Creative
相关产品推荐
相关产品推荐

