从服务启动弹出消息

时间:2019-06-13 16:14:19

标签: c# xamarin.android visual-studio-2017

从服务器收到消息后,我需要从服务启动弹出消息。我可以使用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#编写这些东西。无论如何,我正在寻找解决方案。

2 个答案:

答案 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