ekasetiawans / flutter_background_service

269 stars 189 forks source link

how do I make the service start automatically after restarting the phone? #440

Open NerdyCrow opened 5 months ago

NerdyCrow commented 5 months ago

After restarting the phone, the service does not start automatically. You need to log in to the application, only after that it will start AndroidManifest.xml `

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>

<application
    android:label="background_service"
    android:name="${applicationName}"
    android:icon="@mipmap/ic_launcher">
      <service
        android:name="id.flutter.flutter_background_service.BackgroundService"
        android:foregroundServiceType="specialUse"
    />
    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">
        <!-- Specifies an Android theme to apply to this Activity as soon as
             the Android process has started. This theme is visible to the user
             while the Flutter UI initializes. After that, this theme continues
             to determine the Window background behind the Flutter UI. -->
        <meta-data
          android:name="io.flutter.embedding.android.NormalTheme"
          android:resource="@style/NormalTheme"
          />
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>

    </activity>
    <!-- Don't delete the meta-data below.

         This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->

    <meta-data
        android:name="flutterEmbedding"
        android:value="2" />

</application>

main.dart import 'dart:async'; import 'dart:io'; import 'dart:ui';

import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:flutter_background_service_android/flutter_background_service_android.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:shared_preferences/shared_preferences.dart';

Future main() async { WidgetsFlutterBinding.ensureInitialized(); await initializeService(); runApp(const MyApp()); }

Future initializeService() async { final service = FlutterBackgroundService();

/// OPTIONAL, using custom notification channel id const AndroidNotificationChannel channel = AndroidNotificationChannel( 'my_foreground', // id 'MY FOREGROUND SERVICE', // title description: 'This channel is used for important notifications.', // description importance: Importance.low, // importance must be at low or higher level );

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

if (Platform.isIOS || Platform.isAndroid) { await flutterLocalNotificationsPlugin.initialize( const InitializationSettings( iOS: DarwinInitializationSettings(), android: AndroidInitializationSettings('ic_bg_service_small'), ), ); }

await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel);

await service.configure( androidConfiguration: AndroidConfiguration( // this will be executed when app is in foreground or background in separated isolate onStart: onStart,

  // auto start service
  autoStart: true,
  isForegroundMode: true,
  autoStartOnBoot: true,

  notificationChannelId: 'my_foreground',
  initialNotificationTitle: 'AWESOME SERVICE',
  initialNotificationContent: 'Initializing',
  foregroundServiceNotificationId: 888,
),
iosConfiguration: IosConfiguration(
  // auto start service
  autoStart: true,

  // this will be executed when app is in foreground in separated isolate
  onForeground: onStart,

  // you have to enable background fetch capability on xcode project
  onBackground: onIosBackground,
),

); }

// to ensure this is executed // run app from xcode, then from xcode menu, select Simulate Background Fetch

@pragma('vm:entry-point') Future onIosBackground(ServiceInstance service) async { WidgetsFlutterBinding.ensureInitialized(); DartPluginRegistrant.ensureInitialized();

SharedPreferences preferences = await SharedPreferences.getInstance(); await preferences.reload(); final log = preferences.getStringList('log') ?? []; log.add(DateTime.now().toIso8601String()); await preferences.setStringList('log', log);

return true; }

@pragma('vm:entry-point') void onStart(ServiceInstance service) async { // Only available for flutter 3.0.0 and later DartPluginRegistrant.ensureInitialized();

// For flutter prior to version 3.0.0 // We have to register the plugin manually

SharedPreferences preferences = await SharedPreferences.getInstance(); await preferences.setString("hello", "world");

/// OPTIONAL when use custom notification final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

if (service is AndroidServiceInstance) { service.on('setAsForeground').listen((event) { service.setAsForegroundService(); });

service.on('setAsBackground').listen((event) {
  service.setAsBackgroundService();
});

}

service.on('stopService').listen((event) { service.stopSelf(); });

// bring to foreground Timer.periodic(const Duration(seconds: 1), (timer) async { if (service is AndroidServiceInstance) { if (await service.isForegroundService()) { /// OPTIONAL for use custom notification /// the notification id must be equals with AndroidConfiguration when you call configure() method. flutterLocalNotificationsPlugin.show( 888, 'COOL SERVICE', 'Awesome ${DateTime.now()}', const NotificationDetails( android: AndroidNotificationDetails( 'my_foreground', 'MY FOREGROUND SERVICE', icon: 'ic_bg_service_small', ongoing: true, ), ), );

    // if you don't using custom notification, uncomment this
    service.setForegroundNotificationInfo(
      title: "My App Service",
      content: "Updated at ${DateTime.now()}",
    );
  }
}

/// you can see this log in logcat
print('FLUTTER BACKGROUND SERVICE: ${DateTime.now()}');

// test using external plugin
final deviceInfo = DeviceInfoPlugin();
String? device;
if (Platform.isAndroid) {
  final androidInfo = await deviceInfo.androidInfo;
  device = androidInfo.model;
}

if (Platform.isIOS) {
  final iosInfo = await deviceInfo.iosInfo;
  device = iosInfo.model;
}

service.invoke(
  'update',
  {
    "current_date": DateTime.now().toIso8601String(),
    "device": device,
  },
);

}); }

class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key);

@override State createState() => _MyAppState(); }

class _MyAppState extends State { String text = "Stop Service"; @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Service App'), ), body: Column( children: [ StreamBuilder<Map<String, dynamic>?>( stream: FlutterBackgroundService().on('update'), builder: (context, snapshot) { if (!snapshot.hasData) { return const Center( child: CircularProgressIndicator(), ); }

            final data = snapshot.data!;
            String? device = data["device"];
            DateTime? date = DateTime.tryParse(data["current_date"]);
            return Column(
              children: [
                Text(device ?? 'Unknown'),
                Text(date.toString()),
              ],
            );
          },
        ),
        ElevatedButton(
          child: const Text("Foreground Mode"),
          onPressed: () {
            FlutterBackgroundService().invoke("setAsForeground");
          },
        ),
        ElevatedButton(
          child: const Text("Background Mode"),
          onPressed: () {
            FlutterBackgroundService().invoke("setAsBackground");
          },
        ),
        ElevatedButton(
          child: Text(text),
          onPressed: () async {
            final service = FlutterBackgroundService();
            var isRunning = await service.isRunning();
            if (isRunning) {
              service.invoke("stopService");
            } else {
              service.startService();
            }

            if (!isRunning) {
              text = 'Stop Service';
            } else {
              text = 'Start Service';
            }
            setState(() {});
          },
        ),
        const Expanded(
          child: LogView(),
        ),
      ],
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () {},
      child: const Icon(Icons.play_arrow),
    ),
  ),
);

} }

class LogView extends StatefulWidget { const LogView({Key? key}) : super(key: key);

@override State createState() => _LogViewState(); }

class _LogViewState extends State { late final Timer timer; List logs = [];

@override void initState() { super.initState(); timer = Timer.periodic(const Duration(seconds: 1), (timer) async { final SharedPreferences sp = await SharedPreferences.getInstance(); await sp.reload(); logs = sp.getStringList('log') ?? []; if (mounted) { setState(() {}); } }); }

@override void dispose() { timer.cancel(); super.dispose(); }

@override Widget build(BuildContext context) { return ListView.builder( itemCount: logs.length, itemBuilder: (context, index) { final log = logs.elementAt(index); return Text(log); }, ); } } `

Zer0S2m commented 2 months ago

Good day!

Will there be a solution to this problem or some workarounds?