从服务器收到消息后,我需要从服务启动弹出消息。我可以使用toast
并在应用程序处于前台或后台时显示该消息,正是我需要的,除了我需要捕获对消息的响应之外,因此toast
或{{1} }对我不起作用。我有以下代码:
notification
在服务的这一行中调用此方法:
public async void showMessage(string message)
{
Android.App.AlertDialog.Builder alert = new Android.App.AlertDialog.Builder(this);
alert.SetTitle("Message");
alert.SetMessage(message);
alert.SetPositiveButton("OK", (senderAlert, args) => {
// I need to construct a number of buttons to capture user response, not just "Ok"
});
Dialog dialog = alert.Create();
dialog.Window.SetType(Android.Views.WindowManagerTypes.SystemAlert);
dialog.Show();
//ToastLength duration = ToastLength.Short;
//var toast = Toast.MakeText(context, message, duration);
//toast.Show();
}
我已在清单中设置了所有适当的权限。运行代码时出现错误:
mHandler.Post(() => { showMessage(message); });
这是我的服务代码:
Exception:
Android.Views.WindowManagerBadTokenException
我的清单:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Acr.UserDialogs;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.App;
using Android.Views;
using Android.Widget;
using Java.Lang;
using Java.Util.Concurrent;
using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNet.SignalR.Client.Transports;
namespace MyAndroid
{
[Service]
public class SignalRSrv : Service
{
private bool InstanceFieldsInitialized = false;
private string username = "";
private string firstname = "";
private string lastname = "";
private string company= "";
private string department = "";
private string section = "";
private void InitializeInstanceFields()
{
mBinder = new LocalBinder(this);
}
private Handler mHandler; // to display any received messages
private IBinder mBinder; // Binder given to clients
private SignalRSingleton mInstance;
public SignalRSrv()
{
if (!InstanceFieldsInitialized)
{
InitializeInstanceFields();
InstanceFieldsInitialized = true;
}
}
public override void OnCreate()
{
base.OnCreate();
mInstance = SignalRSingleton.getInstance();
mHandler = new Handler(Looper.MainLooper);
}
public override void OnDestroy()
{
base.OnDestroy();
}
public override IBinder OnBind(Intent intent)
{
//binder = new LocalBinder(this);
User MyUser = new User("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
Bundle bundlee = intent.GetBundleExtra("TheBundle");
MyUser = bundlee.GetParcelable("MyUser") as User;
username = MyUser.Username;
firstname = MyUser.Firstname;
lastname = MyUser.Lastname;
company = intent.GetStringExtra("theSelectedCompany");
department = intent.GetStringExtra("theSelectedDepartment");
section = intent.GetStringExtra("theSelectedSection");
startSignalR();
return mBinder;
}
private void startSignalR()
{
mInstance.setmHubConnection(username, firstname,lastname,company,department,section);
mInstance.setHubProxy();
try
{
// Connect the client to the hup
mInstance.mHubConnection.Start();
mInstance.mHubProxy.On("broadcastMessage", (string platform, string message) =>
{
mHandler.Post(() => { showMessage(message); });
});
}
catch (System.Exception e) when (e is InterruptedException || e is ExecutionException)
{
//opps
var x = 1;
return;
}
}
public async void showMessage(string message)
{
try
{
Android.App.AlertDialog.Builder alert = new Android.App.AlertDialog.Builder(this);
alert.SetTitle("Message");
alert.SetMessage(message);
alert.SetPositiveButton("OK", (senderAlert, args) => {
Toast.MakeText(this, "Ok button Tapped!", ToastLength.Short).Show();
});
Dialog dialog = alert.Create();
dialog.Window.SetType(Android.Views.WindowManagerTypes.Toast);
dialog.Show();
}
catch (System.Exception e)
{
var s = e.Message;
}
//AlertDialog alert = builder.Create();
//alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
//alert.show();
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
User MyUser = new User("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
Bundle bundlee = intent.GetBundleExtra("TheBundle");
MyUser = bundlee.GetParcelable("MyUser") as User;
username = MyUser.Username;
firstname = MyUser.Firstname;
lastname = MyUser.Lastname;
company = intent.GetStringExtra("theSelectedCompany");
department = intent.GetStringExtra("theSelectedDepartment");
section = intent.GetStringExtra("theSelectedsection");
startSignalR();
RegisterForegroundService();
// This tells Android not to restart the service if it is killed to reclaim resources.
return StartCommandResult.Sticky;
}
void RegisterForegroundService()
{
var notification = new NotificationCompat.Builder(this)
.SetContentTitle(Resources.GetString(Resource.String.app_name))
.SetContentText(Resources.GetString(Resource.String.notification_text))
.SetSmallIcon(Resource.Drawable.alert_box)
.SetOngoing(true)
.Build();
// Enlist this instance of the service as a foreground service
StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, notification);
}
}
public class LocalBinder : Binder
{
private readonly SignalRSrv outerInstance;
public LocalBinder(SignalRSrv outerInstance)
{
this.outerInstance = outerInstance;
}
public virtual SignalRSrv Service
{
get
{
// Return this instance of SignalRService so clients can call public methods
return outerInstance;
}
}
}
}
我到处搜索了一个解决方案,发现的所有结果都表明清单中具有适当权限的<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="OML_Android.OML_Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="26" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<service android:name=".SignalRSrv" android:label="Messenger" android:enabled="true"></service>
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"></application>
或Types.SystemAlert
可以解决此问题,但现在看来情况已不再如此。考虑到我发现的所有“解决方案”都使用了4至8年,显然它们已经过时了,更不用说它们是用Java编写的,而不是用c#编写的,这对我来说使一切变得更加难以理解。似乎没有人用c#编写这些东西。无论如何,我正在寻找解决方案。
答案 0 :(得分:0)
可以在xamarin中调用“覆盖其他应用程序”权限:
private const int RequestCode = 1000;
private void CheckForOverlayPermission()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.M) return;
if (!Settings.CanDrawOverlays(this)) return;
var intent = new Intent(Settings.ActionManageOverlayPermission);
intent.SetPackage(PackageName);
StartActivityForResult(intent, RequestCode);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == RequestCode)
{
if (Settings.CanDrawOverlays(this))
{
// we have permission
}
}
base.OnActivityResult(requestCode, resultCode, data);
}
答案 1 :(得分:0)
鉴于android操作系统的最新更新,现在无法执行此操作,因此我不得不推送通知而不是显示弹出窗口。我已经在服务中使用了通知,接下来,我将弄清楚如何在用户点击通知时将其带到前台。我的(正在工作的)服务和通知代码位于以下链接: Send notification from service