You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Kotlin开发Android:APP后台/关闭时从XAMPP服务器获取数据的实现方法

嘿,针对你的需求——即使APP在后台甚至被用户关闭,也要从XAMPP服务器获取数据并触发事件通知,我整理了两个最实用的方案,你可以根据自己的场景来选:

方案一:定时轮询拉取数据(适合服务器无主动推送能力)

如果你的XAMPP服务器没办法主动给APP发消息,用WorkManager是最优解——这是Android Jetpack官方推出的后台任务管理组件,能保证任务在APP后台、甚至被杀死后依然执行(只要设备有电量和网络)。

步骤1:添加WorkManager依赖

在你的Module级build.gradle.kts(或build.gradle)里加入依赖:

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.8.1"
}

步骤2:实现数据拉取Worker

创建一个继承自CoroutineWorker的类,用来处理网络请求和通知逻辑(用协程写异步请求更丝滑):

class DataFetchWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            // 从XAMPP服务器拉取数据
            val latestData = fetchDataFromServer()
            // 判断是否触发通知(根据你的特定事件规则)
            if (isEventTriggered(latestData)) {
                showNotification(latestData)
            }
            // 任务成功,可设置下次执行时间
            Result.success()
        } catch (e: Exception) {
            // 失败则重试(可选,也可以返回Result.failure())
            Result.retry()
        }
    }

    // 封装网络请求逻辑(这里用Retrofit示例,你也可以用OkHttp)
    private suspend fun fetchDataFromServer(): EventData {
        val retrofit = Retrofit.Builder()
            .baseUrl("http://你的XAMPP服务器IP:端口/") // 注意:不能用localhost,要用局域网/公网IP
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val apiService = retrofit.create(ServerApi::class.java)
        return apiService.getLatestEventData()
    }

    // 自定义判断逻辑:是否需要触发通知
    private fun isEventTriggered(data: EventData): Boolean {
        return data.hasNewEvent // 替换成你的实际判断条件
    }

    // 生成并显示通知
    private fun showNotification(data: EventData) {
        val notificationManager = applicationContext
            .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // 适配Android 8.0+的通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "EVENT_NOTIFICATION_CHANNEL",
                "事件通知",
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                description = "来自服务器的事件提醒"
            }
            notificationManager.createNotificationChannel(channel)
        }

        val notification = NotificationCompat.Builder(applicationContext, "EVENT_NOTIFICATION_CHANNEL")
            .setContentTitle("新事件提醒")
            .setContentText(data.eventDetails)
            .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .build()

        notificationManager.notify(1001, notification)
    }
}

// 你的API接口定义
interface ServerApi {
    @GET("api/latest-event") // 替换成你的XAMPP服务器接口路径
    suspend fun getLatestEventData(): EventData
}

// 数据模型类,根据你的接口返回定义
data class EventData(
    val hasNewEvent: Boolean,
    val eventDetails: String
)

步骤3:启动定时任务

在APP启动时(比如Application类的onCreate,或者主Activity的onCreate)初始化定时任务:

// 构建定时请求:每15分钟执行一次(最小间隔是15分钟,系统会根据情况调整)
val fetchWorkRequest = PeriodicWorkRequestBuilder<DataFetchWorker>(15, TimeUnit.MINUTES)
    // 可选:设置任务执行的约束条件,比如仅在有网络时执行
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()
    )
    .build()

// 加入WorkManager队列,确保同一任务只会存在一个实例
WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork(
    "DataFetchTask",
    ExistingPeriodicWorkPolicy.KEEP, // 如果已有任务存在,保留原任务
    fetchWorkRequest
)

方案二:服务器主动推送(实时性更高)

如果希望服务器有新事件时立即通知APP,而不是等轮询,推荐用**Firebase Cloud Messaging(FCM)**结合XAMPP的PHP后台实现主动推送,实时性拉满。

步骤1:集成FCM到Android项目

  1. 去Firebase控制台创建项目,添加你的Android应用,下载google-services.json放到APP模块根目录。
  2. 在Module级build.gradle.kts添加依赖:
dependencies {
    implementation platform("com.google.firebase:firebase-bom:32.7.0")
    implementation "com.google.firebase:firebase-messaging-ktx"
}

步骤2:实现FCM消息处理服务

创建一个继承自FirebaseMessagingService的类,用来处理收到的推送消息:

class AppFirebaseMessagingService : FirebaseMessagingService() {

    // 当收到推送消息时触发
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        // 处理通知消息(FCM自带的通知格式)
        remoteMessage.notification?.let {
            showNotification(it.title ?: "新提醒", it.body ?: "有新事件发生")
        }
        // 处理自定义数据消息(你可以从这里拿到服务器传的自定义数据)
        remoteMessage.data.let { data ->
            val eventTitle = data["event_title"] ?: "新事件"
            val eventContent = data["event_content"] ?: "服务器检测到新事件"
            showNotification(eventTitle, eventContent)
        }
    }

    // 获取并上传设备令牌到XAMPP服务器(用来指定推送目标)
    override fun onNewToken(token: String) {
        super.onNewToken(token)
        // 这里写上传token到你的XAMPP服务器的逻辑,比如用Retrofit/post请求
        uploadDeviceToken(token)
    }

    private fun showNotification(title: String, content: String) {
        // 通知逻辑和方案一类似,注意用不同的通知渠道ID
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "FCM_EVENT_CHANNEL",
                "FCM事件通知",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }
        val notification = NotificationCompat.Builder(this, "FCM_EVENT_CHANNEL")
            .setContentTitle(title)
            .setContentText(content)
            .setSmallIcon(R.drawable.ic_notification)
            .build()
        notificationManager.notify(1002, notification)
    }

    private suspend fun uploadDeviceToken(token: String) {
        // 实现上传token到XAMPP服务器的逻辑
        val retrofit = Retrofit.Builder()
            .baseUrl("http://你的XAMPP服务器IP:端口/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val apiService = retrofit.create(ServerApi::class.java)
        apiService.uploadDeviceToken(mapOf("token" to token))
    }
}

// 补充ServerApi的上传接口
interface ServerApi {
    // ... 其他接口
    @POST("api/save-token")
    suspend fun uploadDeviceToken(@Body token: Map<String, String>)
}

步骤3:在XAMPP后台编写推送脚本

当你的XAMPP服务器检测到特定事件时,调用PHP脚本发送FCM推送:

<?php
// 发送FCM推送的函数
function sendFCMPush($deviceToken, $title, $content) {
    $fcmUrl = 'https://fcm.googleapis.com/fcm/send';
    // 从Firebase控制台获取你的服务器密钥
    $serverKey = "你的FCM服务器密钥";
    
    $payload = [
        'to' => $deviceToken,
        'notification' => [
            'title' => $title,
            'body' => $content
        ],
        'data' => [
            'event_title' => $title,
            'event_content' => $content
        ]
    ];
    
    $headers = [
        'Authorization: key=' . $serverKey,
        'Content-Type: application/json'
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $fcmUrl);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    $result = curl_exec($ch);
    curl_close($ch);
    
    return $result;
}

// 示例:当检测到新事件时调用
// 从数据库获取保存的设备令牌
$deviceToken = "从数据库读取的用户设备令牌";
sendFCMPush($deviceToken, "紧急事件提醒", "服务器检测到新的特定事件!");
?>

关键注意事项
  1. XAMPP服务器可访问性:测试时确保手机和服务器在同一局域网,用服务器的局域网IP(比如192.168.1.100),不要用localhost;上线时需要将服务器部署到公网,或用内网穿透工具临时测试。
  2. 权限配置:在AndroidManifest.xml里添加必要权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  1. 后台限制适配:Android 8.0+对后台服务有严格限制,WorkManager和FCM都是官方推荐的合规方案,避免被系统杀死。

内容的提问来源于stack exchange,提问作者Prem Buddhbhatti

火山引擎 最新活动