Xamarin Android 后台一直运行 后台定位

一、开发环境:

VS2019-16.10.0

Xamarin-16.10.000.228

Xamarin.Android SDK-11.3.0.1

荣耀20Pro真机调试

二、预实现目的

使程序可以一直保持后台运行,进行定位,并且程序可以开机自启。

三、详细方法

原理:通过创建前台服务的方式保持App处于活动状态。

1.AndroidManifest.xml配置权限

   <application android:label="MyTest" android:theme="@style/MainTheme" android:icon="@drawable/icon" android:debuggable="true" android:allowBackup="true">
		<!--前台服务想要调用定位功能,必须加上这个;服务名字前面要加上命名空间,MyTest.Droid就是我的服务类所在命名空间-->
		<service android:name="MyTest.Droid.GaodeService" android:foregroundServiceType="location" />
	
	</application>


    <!--允许程序打开网络套接字-->
	<uses-permission android:name="android.permission.INTERNET" />
	<!--允许程序设置内置sd卡的写权限-->
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<!--允许程序获取网络状态-->
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<!--允许程序访问WiFi网络信息-->
	<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
	<!--允许程序读写手机状态和身份-->
	<uses-permission android:name="android.permission.READ_PHONE_STATE" />
	<!--允许程序访问CellID或WiFi热点来获取粗略的位置-->
	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
	<!--用于访问GPS定位-->
	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
	<!--这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
	<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
	<!--这个权限用于允许程序在手机屏幕关闭后后台进程仍然运行-->
	<uses-permission android:name="android.permission.WAKE_LOCK" />
	<!--用于申请获取蓝牙信息进行室内定位-->
	<uses-permission android:name="android.permission.BLUETOOTH" />
	<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
	<!--用于申请调用A-GPS模块-->
	<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
	<!--用于创建前台服务-->
	<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

2.创建通知管道

创建最简单最粗略的通知管道的方法,主要的参数是管道id,创建通知时要使用

public static void CreateNotificationChannel(Context context, string channelID, string channelName)
        {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                ((NotificationManager)context.GetSystemService(Context.NotificationService))
                            .CreateNotificationChannel(new NotificationChannel(channelID, channelName, NotificationImportance.Default));
            }
        }

3.创建通知

下面是创建通知的简化方法, 一个通知标题,文本,图标,一个前台服务貌似必须设置为True的项, 通知管道id在NotificationCompat.Builder构造函数填入

public static Notification CreateServerNotification(string contentTitle, string contentText, Context context, string channelID)
        {
            return new NotificationCompat.Builder(context, channelID)
                               .SetContentTitle(contentTitle)
                               .SetContentText(contentText)
                               .SetSmallIcon(Resource.Mipmap.icon)
                               .SetOngoing(true)
                               .Build();
        }

4.开启服务的方法

android 8.0及以上版本开启前台服务需要使用StartForegroundService,这个方法可以放在你想要调用服务的类中,比如MainActivity

public static void StartServer(Context context, Intent intent)
        {
            context.StartForegroundService(intent);
        }

5.声明服务

[Service]  //此处Service不可写成Service(IsolatedProcess=true),否则普通调用服务方法不起作用
    public sealed class MyServer : Service
    {
        
        public override void OnCreate()
        {
            base.OnCreate();

            //此处在第一次调用服务,即服务创建时触发,第二次及以后再调用不会再触发
            const int NOTIFICATION_ID = 345;

            const string CHANNEL_ID = "自己起一个id";

            const string CHANNEL_NAME = "自己起一个name";

            CreateNotificationChannel(this, CHANNEL_ID, CHANNEL_NAME);

            var notification = CreateServerNotification("标题", "内容", this, CHANNEL_ID);

            StartForeground(NOTIFICATION_ID, notification);
        }


        [return: GeneratedEnum]
        public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
        {
               //此处可添加自己想要通过前台服务做的事情,比如后台定位功能,每次调用服务都会触发
               //startlocation()
            return StartCommandResult.RedeliverIntent;  //此返回值可以在服务被终止时尝试重启服务,并可传回当时的Intent
        }


      
        public override void OnDestroy()
        {
            base.OnDestroy();
        }

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }
    }

6.在MainActivity中调用服务

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IAMapLocationListener
    {

//...

 protected override void OnStart()
        {
            base.OnStart();
           Intent serviceToStart = new Intent(this, typeof(MyServer));
           StartServer(this, serviceToStart);
           
        }
 public static void StartServer(ContextWrapper context, Intent intent)
        {
            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
            {

                context.StartForegroundService(intent);

            }
            else
            {
                context.StartService(intent);
            }
        }

//...

}

四、注意事项

服务本身还会受到下面一些因素的影响

1.是否允许后台活动,

2.是否忽略电池优化

3.针对荣耀机型,

1>可以在“手机管家-应用启动管理”中设置应用手动管理,允许后台运行。

2>打开应用后,在手机任务列表视图中,下拉app界面,app右上角会有小锁图标出现,手机就会把app加入保护列表,不会随便杀死该app。

Xamarin Android 后台一直运行 后台定位


参考连接:

Xamarin Android 创建前台服务的个人粗略总结 - 雷开封 - 博客园 (cnblogs.com)

服务概览  |  Android 开发者  |  Android Developers (google.cn)

Foreground services  |  Android 开发者  |  Android Developers (google.cn)

Xamarin.Android服务的实现 - y-z-f - 博客园 (cnblogs.com)

上一篇:局部敏感哈希算法(Locality Sensitive Hashing)


下一篇:带你一步一步深入Handler源码,妈妈再也不用担心我找工作了!