Bagaimana cara memberikan notifikasi di Android pada waktu tertentu di Android Oreo?

Saya mencari cara untuk membuat preference di Settings untuk mengirim pemberitahuan pada waktu tertentu (ditetapkan oleh pengguna dalam pengaturan) di aplikasi Android. Saya telah melihat thread yang berbeda seperti ini, namun ini tidak berfungsi di Android Oreo.

Dapatkah seseorang membantu saya dengan ini atau mengarahkan saya ke tutorial?


person Tricky Bay    schedule 14.07.2018    source sumber
comment
Karena tidak ada yang merespons...Apakah notifikasi benar-benar harus dikirim pada waktu tertentu? Dalam banyak kasus tidak, namun jika jawabannya adalah ya maka AlarmManager.setAlarmClock adalah satu-satunya alternatif lokal yang realistis. Solusi lainnya adalah dengan menggunakan FCM prioritas tinggi: Firebase Cloud Message. Jika penundaan hingga ~10 menit dapat ditoleransi maka sesuatu seperti AlarmManager.setExactAndAllowWhileIdle mungkin berguna. Jika tidak, lihat apakah aplikasi Anda dapat mentoleransi penggunaan JobScheduler.   -  person Elletlar    schedule 16.07.2018
comment
Ya, saya ingin mengirim notifikasi harian pada waktu yang ditentukan pengguna. Alarm Manager dapat bekerja dalam kasus saya, namun saya mencari metode implementasi. Tutorial yang berfungsi untuk Android Oreo, tepatnya.   -  person Tricky Bay    schedule 17.07.2018


Jawaban (2)


Setelah melihat postingan berbeda dan beberapa penelitian tentang implementasi AlarmManager, inilah yang berhasil bagi saya.

Dasar untuk ini adalah postingan ini dan Jadwalkan Pengulangan Alarm Android Dokumentasi.

Ini adalah implementasi saya saat ini:

Saya memiliki implementasi SwitchPreference dan TimePicker adalah Settings

SwitchPreference untuk menanyakan apakah pengguna ingin mengaktifkan Pemberitahuan Harian Berulang.

TimePicker untuk mengatur waktu Pemberitahuan.

Dalam metode OnCreate MainActivity atau di mana pun Anda membaca SharedPreferences lakukan ini:

PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
Boolean dailyNotify = sharedPref.getBoolean(SettingsActivity.KEY_PREF_DAILY_NOTIFICATION, true);
PackageManager pm = this.getPackageManager();
ComponentName receiver = new ComponentName(this, DeviceBootReceiver.class);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

// if user enabled daily notifications
if (dailyNotify) {
    //region Enable Daily Notifications
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, sharedPref.getInt("dailyNotificationHour", 7));
    calendar.set(Calendar.MINUTE, sharedPref.getInt("dailyNotificationMin", 15));
    calendar.set(Calendar.SECOND, 1);
    // if notification time is before selected time, send notification the next day
    if (calendar.before(Calendar.getInstance())) {
        calendar.add(Calendar.DATE, 1);
    }
    if (manager != null) {
        manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                AlarmManager.INTERVAL_DAY, pendingIntent);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        }
    }
    //To enable Boot Receiver class
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);
    //endregion
} else { //Disable Daily Notifications
    if (PendingIntent.getBroadcast(this, 0, alarmIntent, 0) != null && manager != null) {
        manager.cancel(pendingIntent);
        //Toast.makeText(this,"Notifications were disabled",Toast.LENGTH_SHORT).show();
    }
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);
}

Selanjutnya tambahkan kelas AlarmReceiver yang mengimplementasikan BroadcastReceiver seperti ini:

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(context));
    SharedPreferences.Editor sharedPrefEditor = prefs.edit();

    NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    Intent notificationIntent = new Intent(context, MainActivity.class);

    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
            | Intent.FLAG_ACTIVITY_SINGLE_TOP);

    PendingIntent pendingI = PendingIntent.getActivity(context, 0,
            notificationIntent, 0);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("default",
                    "Daily Notification",
                    NotificationManager.IMPORTANCE_DEFAULT);
            channel.setDescription("Daily Notification");
            if (nm != null) {
                nm.createNotificationChannel(channel);
            }
        }
        NotificationCompat.Builder b = new NotificationCompat.Builder(context, "default");
        b.setAutoCancel(true)
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher_foreground)
                .setTicker("{Time to watch some cool stuff!}")
                .setContentTitle("My Cool App")
                .setContentText("Time to watch some cool stuff!")
                .setContentInfo("INFO")
                .setContentIntent(pendingI);

        if (nm != null) {
            nm.notify(1, b.build());
            Calendar nextNotifyTime = Calendar.getInstance();
            nextNotifyTime.add(Calendar.DATE, 1);
            sharedPrefEditor.putLong("nextNotifyTime", nextNotifyTime.getTimeInMillis());
            sharedPrefEditor.apply();
        }
    }
}

Sistem akan mematikan AlarmManager jika Perangkat dimatikan atau di-boot ulang, jadi mulai ulang lagi di BOOT COMPLETE tambahkan kelas ini:

public class DeviceBootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    if (Objects.equals(intent.getAction(), "android.intent.action.BOOT_COMPLETED")) {
        // on device boot complete, reset the alarm
        Intent alarmIntent = new Intent(context, AlarmReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);

        AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(context));

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.HOUR_OF_DAY, sharedPref.getInt("dailyNotificationHour", 7));
        calendar.set(Calendar.MINUTE, sharedPref.getInt("dailyNotificationMin", 15));
        calendar.set(Calendar.SECOND, 1);

        Calendar newC = new GregorianCalendar();
        newC.setTimeInMillis(sharedPref.getLong("nextNotifyTime", Calendar.getInstance().getTimeInMillis()));

        if (calendar.after(newC)) {
            calendar.add(Calendar.HOUR, 1);
        }

        if (manager != null) {
            manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                    AlarmManager.INTERVAL_DAY, pendingIntent);
        }
    }
}
}

Dan Terakhir jangan lupa tambahkan izin ini ke AndroidManidest:

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

dan daftarkan penerima Anda di AndroidManifest

<application
    <!--YOUR APPLICATION STUFF-->

    <receiver android:name=".DeviceBootReceiver"
        android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <receiver android:name=".AlarmReceiver" />

Notification harus disetel dengan ini pada waktu tertentu yang ditentukan oleh TimePicker dan jika pengguna mengaktifkan SwitchPreference.

person Tricky Bay    schedule 02.08.2018

Ada banyak sekali contoh cara melakukan ini di StackOverflow, namun sayangnya tidak ada satupun yang berfungsi lagi karena Google mengubah cara kerja AlarmManager.

  • Android 6: Istirahatkan
  • Android 7: Istirahatkan Agresif [Menonaktifkan CPU segera setelah layar dimatikan]
  • Android 8: Pembatasan tambahan pada layanan latar belakang

Opsi AlarmManager satu-satunya yang memungkinkan pengembang membangunkan perangkat pada waktu tertentu adalah AlarmManager.setAlarmClock.

Menggunakan setAlarmClock

Selain alarm, Anda dapat mengatur maksud yang memungkinkan Anda meluncurkan aplikasi saat alarm diklik.

Perangkat juga dapat dibangunkan pada waktu tertentu menggunakan FCM prioritas tinggi, Firebase Cloud Message.

Namun ringkasnya, tidak ada pilihan lain: 'setExact' dan metode terkait tidak lagi berfungsi sesuai dengan namanya yang diiklankan.

person Elletlar    schedule 17.07.2018