mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
new: custom foreground service on Android (#556)
This commit is contained in:
@@ -53,7 +53,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId "tech.lolli.toolbox"
|
applicationId "tech.lolli.toolbox"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
@@ -15,7 +16,8 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:hasFragileUserData="true"
|
android:hasFragileUserData="true"
|
||||||
android:restoreAnyVersion="true">
|
android:restoreAnyVersion="true"
|
||||||
|
tools:targetApi="q">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
@@ -43,11 +45,6 @@
|
|||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
|
||||||
<service
|
|
||||||
android:name="id.flutter.flutter_background_service.BackgroundService"
|
|
||||||
android:foregroundServiceType="dataSync"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".widget.HomeWidget"
|
android:name=".widget.HomeWidget"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
@@ -68,8 +65,9 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".MyForegroundService"
|
android:name=".ForegroundService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
|
android:foregroundServiceType="dataSync"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ import android.app.*
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
|
|
||||||
class MyForegroundService : Service() {
|
class ForegroundService : Service() {
|
||||||
|
private val chanId = "ForegroundServiceChannel"
|
||||||
private val CHANNEL_ID = "ForegroundServiceChannel"
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
@@ -31,8 +29,8 @@ class MyForegroundService : Service() {
|
|||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val serviceChannel = NotificationChannel(
|
val serviceChannel = NotificationChannel(
|
||||||
CHANNEL_ID,
|
chanId,
|
||||||
CHANNEL_ID,
|
chanId,
|
||||||
NotificationManager.IMPORTANCE_DEFAULT
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
)
|
)
|
||||||
val manager = getSystemService(NotificationManager::class.java)
|
val manager = getSystemService(NotificationManager::class.java)
|
||||||
@@ -49,11 +47,20 @@ class MyForegroundService : Service() {
|
|||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
return NotificationCompat.Builder(this, CHANNEL_ID)
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
.setContentTitle("App is running")
|
Notification.Builder(this, chanId)
|
||||||
.setContentText("Click to open the app")
|
.setContentTitle("App is running")
|
||||||
.setSmallIcon(R.drawable.ic_notification)
|
.setContentText("Click to open the app")
|
||||||
.setContentIntent(pendingIntent)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
.build()
|
.setContentIntent(pendingIntent)
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
Notification.Builder(this)
|
||||||
|
.setContentTitle("App is running")
|
||||||
|
.setContentText("Click to open the app")
|
||||||
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
package tech.lolli.toolbox
|
package tech.lolli.toolbox
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.Manifest
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
@@ -18,7 +23,8 @@ class MainActivity: FlutterFragmentActivity() {
|
|||||||
result.success(null)
|
result.success(null)
|
||||||
}
|
}
|
||||||
"startService" -> {
|
"startService" -> {
|
||||||
val serviceIntent = Intent(this, ForegroundService::class.java)
|
reqPerm()
|
||||||
|
val serviceIntent = Intent(this@MainActivity, ForegroundService::class.java)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
startForegroundService(serviceIntent)
|
startForegroundService(serviceIntent)
|
||||||
} else {
|
} else {
|
||||||
@@ -32,4 +38,16 @@ class MainActivity: FlutterFragmentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun reqPerm() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
|
||||||
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
this,
|
||||||
|
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||||
|
123,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:flutter_displaymode/flutter_displaymode.dart';
|
|||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:server_box/app.dart';
|
import 'package:server_box/app.dart';
|
||||||
|
import 'package:server_box/core/channel/bg_run.dart';
|
||||||
import 'package:server_box/core/utils/sync/icloud.dart';
|
import 'package:server_box/core/utils/sync/icloud.dart';
|
||||||
import 'package:server_box/core/utils/sync/webdav.dart';
|
import 'package:server_box/core/utils/sync/webdav.dart';
|
||||||
import 'package:server_box/data/model/app/menu/server_func.dart';
|
import 'package:server_box/data/model/app/menu/server_func.dart';
|
||||||
@@ -109,6 +110,10 @@ void _doPlatformRelated() async {
|
|||||||
if (isAndroid) {
|
if (isAndroid) {
|
||||||
// try switch to highest refresh rate
|
// try switch to highest refresh rate
|
||||||
FlutterDisplayMode.setHighRefreshRate();
|
FlutterDisplayMode.setHighRefreshRate();
|
||||||
|
if (Stores.setting.bgRun.fetch()) {
|
||||||
|
Loggers.app.info('Start foreground service');
|
||||||
|
BgRunMC.startService();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final serversCount = Stores.server.box.keys.length;
|
final serversCount = Stores.server.box.keys.length;
|
||||||
|
|||||||
@@ -259,11 +259,11 @@ class _AddPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const viewPadding = 3.0;
|
const viewPadding = 7.0;
|
||||||
final viewWidth = context.media.size.width - 2 * viewPadding;
|
final viewWidth = context.media.size.width - 2 * viewPadding;
|
||||||
|
|
||||||
final itemCount = ServerProvider.servers.length;
|
final itemCount = ServerProvider.servers.length;
|
||||||
const itemPadding = 3.0;
|
const itemPadding = 1.0;
|
||||||
const itemWidth = 150.0;
|
const itemWidth = 150.0;
|
||||||
const itemHeight = 50.0;
|
const itemHeight = 50.0;
|
||||||
|
|
||||||
@@ -272,62 +272,55 @@ class _AddPage extends StatelessWidget {
|
|||||||
max(viewWidth ~/ (visualCrossCount * itemPadding + itemWidth), 1);
|
max(viewWidth ~/ (visualCrossCount * itemPadding + itemWidth), 1);
|
||||||
final mainCount = itemCount ~/ crossCount + 1;
|
final mainCount = itemCount ~/ crossCount + 1;
|
||||||
|
|
||||||
return Center(
|
return ServerProvider.serverOrder.listenVal((order) {
|
||||||
key: const Key('sshTabAddServer'),
|
if (order.isEmpty) {
|
||||||
child: ServerProvider.serverOrder.listenVal((order) {
|
return Center(
|
||||||
if (order.isEmpty) {
|
child: Text(libL10n.empty, textAlign: TextAlign.center),
|
||||||
return Center(
|
);
|
||||||
child: Text(libL10n.empty, textAlign: TextAlign.center),
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom grid
|
// Custom grid
|
||||||
return ListView(
|
return ListView(
|
||||||
padding: const EdgeInsets.all(viewPadding),
|
padding: const EdgeInsets.all(viewPadding),
|
||||||
children: List.generate(
|
children: List.generate(
|
||||||
mainCount,
|
mainCount,
|
||||||
(rowIndex) => Row(
|
(rowIndex) => Row(
|
||||||
children: List.generate(crossCount, (columnIndex) {
|
children: List.generate(crossCount, (columnIndex) {
|
||||||
final idx = rowIndex * crossCount + columnIndex;
|
final idx = rowIndex * crossCount + columnIndex;
|
||||||
final id = order.elementAtOrNull(idx);
|
final id = order.elementAtOrNull(idx);
|
||||||
if (id == null) return _placeholder;
|
final spi = ServerProvider.pick(id: id)?.value.spi;
|
||||||
|
if (spi == null) return _placeholder;
|
||||||
|
|
||||||
final spi = ServerProvider.pick(id: order[idx])?.value.spi;
|
return Expanded(
|
||||||
if (spi == null) return _placeholder;
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(itemPadding),
|
||||||
return Expanded(
|
child: InkWell(
|
||||||
child: Padding(
|
onTap: () => onTapInitCard(spi),
|
||||||
padding: const EdgeInsets.all(itemPadding),
|
child: Container(
|
||||||
child: CardX(
|
height: itemHeight,
|
||||||
child: InkWell(
|
alignment: Alignment.centerLeft,
|
||||||
onTap: () => onTapInitCard(spi),
|
padding: const EdgeInsets.only(left: 17, right: 7),
|
||||||
child: Container(
|
child: Row(
|
||||||
height: itemHeight,
|
children: [
|
||||||
alignment: Alignment.centerLeft,
|
Expanded(
|
||||||
padding: const EdgeInsets.only(left: 17, right: 7),
|
child: Text(
|
||||||
child: Row(
|
spi.name,
|
||||||
children: [
|
style: UIs.text18,
|
||||||
Expanded(
|
maxLines: 1,
|
||||||
child: Text(
|
overflow: TextOverflow.ellipsis,
|
||||||
spi.name,
|
),
|
||||||
style: UIs.text18,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Icon(Icons.chevron_right)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
const Icon(Icons.chevron_right)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
).cardx,
|
||||||
);
|
),
|
||||||
}),
|
);
|
||||||
),
|
}),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
}),
|
);
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user