Android应用添加日历提醒功能

Android应用添加日历提醒功能

功能

在安卓应用里调用系统日历,直接创建一个带提醒的日历事件,甚至不需要跳转到日历界面,只需要获取系统日历的读取权限即可。

需要的权限

在AndroidManifest.xml里添加

xml

复制代码

注意: 如果是Android 6.0(API 23)以上,需要动态申请权限。

代码

创建一个CalendarHelper工具类,包含:

获取系统日历账户

自动写入事件

添加提醒

自动处理没有日历账户的情况(可提示用户手动创建)

动态申请权限(当用户拒绝权限时,我这里会弹出一个提示框,提示的内容可以从外部传入,也可以使用默认的。或者你不是使用默认,直接打开系统的设置页面也是可以的(下面屏蔽了这部分的代码))

判断是否已存在相同时间的逻辑,避免重复添加

java

复制代码

package com.cocos.calender;

import android.app.Activity;

import android.Manifest;

import android.content.ContentUris;

import android.content.ContentValues;

import android.content.Context;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.database.Cursor;

import android.net.Uri;

import android.provider.CalendarContract;

import android.provider.Settings;

import android.text.TextUtils;

import android.util.Log;

import androidx.annotation.NonNull;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

import java.util.Calendar;

import java.util.TimeZone;

import org.json.JSONObject;

import org.json.JSONException;

import android.widget.Toast;

public class CalendarHelper {

private static final String TAG = "CalendarHelper";

/** 用来存放拒绝权限时的提示语 */

private static String denyPermissionMessage = "未获得日历权限,无法添加提醒事件";

/** 日历权限请求码 */

public static final int REQUEST_CALENDAR_PERMISSION = 1010;

/** 临时存储待执行事件 */

private static PendingEvent pendingEvent;

private static class PendingEvent {

String title;

String description;

String location;

long beginTime;

long endTime;

int reminderMinutes;

PendingEvent(String title, String description, String location,

long beginTime, long endTime, int reminderMinutes) {

this.title = title;

this.description = description;

this.location = location;

this.beginTime = beginTime;

this.endTime = endTime;

this.reminderMinutes = reminderMinutes;

}

}

/**

* 检查权限并添加事件(带权限请求)

*/

public static void addEventWithPermission(Activity activity,

String title,

String description,

String location,

long beginTimeMillis,

long endTimeMillis,

int reminderMinutes) {

// 检查日历读写权限

if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_CALENDAR)

!= PackageManager.PERMISSION_GRANTED

|| ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_CALENDAR)

!= PackageManager.PERMISSION_GRANTED) {

// 保存事件等待用户授权

pendingEvent = new PendingEvent(title, description, location, beginTimeMillis, endTimeMillis, reminderMinutes);

// 这里可以加解释,但不强制

if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.READ_CALENDAR)) {

Log.i(TAG, "需要日历权限来添加提醒事件");

}

// ✅ 直接请求权限(即使用户上次拒绝,这里依旧会再弹一次)

ActivityCompat.requestPermissions(activity,

new String[]{Manifest.permission.READ_CALENDAR,

Manifest.permission.WRITE_CALENDAR},

REQUEST_CALENDAR_PERMISSION);

} else {

// 权限已授权,直接添加

addEvent(activity, title, description, location, beginTimeMillis, endTimeMillis, reminderMinutes);

}

}

/**

* 在 Activity 的 onRequestPermissionsResult 中调用

*/

public static void onRequestPermissionsResultCalendar(Activity activity,

int requestCode,

@NonNull int[] grantResults) {

if (requestCode == REQUEST_CALENDAR_PERMISSION) {

if (grantResults.length >= 2

&& grantResults[0] == PackageManager.PERMISSION_GRANTED

&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {

Log.i(TAG, "日历权限申请成功");

if (pendingEvent != null) {

addEvent(activity,

pendingEvent.title,

pendingEvent.description,

pendingEvent.location,

pendingEvent.beginTime,

pendingEvent.endTime,

pendingEvent.reminderMinutes);

pendingEvent = null;

}

} else {

Log.e(TAG, "用户拒绝了日历权限");

Toast.makeText(activity,

denyPermissionMessage,

Toast.LENGTH_SHORT).show();

// 如果用户永久拒绝,可跳转设置

// if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, android.Manifest.permission.READ_CALENDAR)) {

// Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

// intent.setData(Uri.parse("package:" + activity.getPackageName()));

// activity.startActivity(intent);

// }

}

}

}

/** 获取系统日历账户 ID */

private static long getCalendarAccountId(Context context) {

Cursor userCursor = context.getContentResolver().query(

CalendarContract.Calendars.CONTENT_URI,

new String[]{CalendarContract.Calendars._ID},

null, null, null);

if (userCursor != null) {

try {

if (userCursor.moveToFirst()) {

return userCursor.getLong(0);

}

} finally {

userCursor.close();

}

}

return -1;

}

/** 判断事件是否已存在(避免重复) */

private static boolean isEventAlreadyExists(Context context, String title, long beginTimeMillis) {

long oneMinuteBefore = beginTimeMillis - 60 * 1000;

long oneMinuteAfter = beginTimeMillis + 60 * 1000;

Cursor cursor = context.getContentResolver().query(

CalendarContract.Events.CONTENT_URI,

new String[]{CalendarContract.Events._ID},

CalendarContract.Events.TITLE + "=? AND " +

CalendarContract.Events.DTSTART + ">=? AND " +

CalendarContract.Events.DTSTART + "<=?",

new String[]{title, String.valueOf(oneMinuteBefore), String.valueOf(oneMinuteAfter)},

null

);

if (cursor != null) {

try {

if (cursor.moveToFirst()) {

return true; // 已存在

}

} finally {

cursor.close();

}

}

return false;

}

/** 插入日历事件 + 提醒 */

private static boolean addEvent(Context context,

String title,

String description,

String location,

long beginTimeMillis,

long endTimeMillis,

int reminderMinutes) {

long calId = getCalendarAccountId(context);

if (calId == -1) {

Log.e(TAG, "没有找到系统日历账户,请先在系统日历中添加一个账户");

return false;

}

if (isEventAlreadyExists(context, title, beginTimeMillis)) {

Log.w(TAG, "事件已存在,跳过添加: " + title);

return false;

}

ContentValues eventValues = new ContentValues();

eventValues.put(CalendarContract.Events.CALENDAR_ID, calId);

eventValues.put(CalendarContract.Events.TITLE, TextUtils.isEmpty(title) ? "未命名事件" : title);

eventValues.put(CalendarContract.Events.DESCRIPTION, description);

eventValues.put(CalendarContract.Events.EVENT_LOCATION, location);

eventValues.put(CalendarContract.Events.DTSTART, beginTimeMillis);

eventValues.put(CalendarContract.Events.DTEND, endTimeMillis);

eventValues.put(CalendarContract.Events.HAS_ALARM, 1);

eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());

Uri newEvent = context.getContentResolver().insert(CalendarContract.Events.CONTENT_URI, eventValues);

if (newEvent == null) {

Log.e(TAG, "插入日历事件失败");

return false;

}

long eventId = ContentUris.parseId(newEvent);

ContentValues reminderValues = new ContentValues();

reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventId);

reminderValues.put(CalendarContract.Reminders.MINUTES, reminderMinutes);

reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);

Uri reminderUri = context.getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, reminderValues);

if (reminderUri == null) {

Log.e(TAG, "插入提醒失败");

return false;

}

Log.i(TAG, "日历事件添加成功,eventId=" + eventId);

return true;

}

public static void creatroCalendarReminder(Context context,String data){

try {

// 将传入的字符串转成 JSON 对象

JSONObject json = new JSONObject(data);

// 从 JSON 中取字段,如果没有就用默认值

String title = json.optString("title", "测试");

String description = json.optString("description", "测试");

String location = json.optString("location", "测试");

int startHour = json.optInt("startHour", 1);

int startMinute = json.optInt("startMinute", 10);

int endHour = json.optInt("endHour", startHour + 1);

Calendar begin = Calendar.getInstance();

begin.add(Calendar.DAY_OF_MONTH, 0); // 哪天开始,Calendar.DAY_OF_MONTH当前时间 + 后面参数值,比如我这里为0,就是今天,如果为1就是明天

begin.set(Calendar.HOUR_OF_DAY, startHour); // 开始的小时,这里是24小时制 startHour的取值范围为0~23

begin.set(Calendar.MINUTE, startMinute); // 开始的分钟

Calendar end = (Calendar) begin.clone();

end.set(Calendar.HOUR_OF_DAY, endHour); // 结束的时间,参数和上面开始时间一样,赋值方式为end.set()

if (context == null) {

Log.e("Calendar", "Context is null");

return;

}

// 添加事件

CalendarHelper.addEventWithPermission(

(Activity) context,

title,

description,

location,

begin.getTimeInMillis(), //事件开始时间的毫秒值

end.getTimeInMillis(), //事件结束时间的毫秒值

5 // 提前5分钟提醒

);

} catch (JSONException e) {

e.printStackTrace();

Log.e("Calendar", "JSON解析失败:" + data);

}

}

/**

* 从外部传提示文本过来

* @param message

*/

public static void setDenyPermissionMessage(String message) {

if (!TextUtils.isEmpty(message)) {

denyPermissionMessage = message;

}

}

}

Activity中的逻辑

先在Activity中引入CalendarHelper类,并调用CalendarHelper.creatroCalendarReminder()方法,传入参数,实现日历添加功能。

java

复制代码

@Override

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

// 处理日历权限

if (requestCode == CalendarHelper.REQUEST_CALENDAR_PERMISSION) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

CalendarHelper.onRequestPermissionsResultCalendar(this, requestCode, grantResults);

}

}

}

添加创建日历提醒事件和传入提示文本

java

复制代码

/**

* 创建日历提醒事件

* @param data

*/

public static void creatroCalendarReminder(String data){

Context context = AppActivity.getInstance();

CalendarHelper.creatroCalendarReminder(context,data);

}

/**

* 获取读取日历权限被拒绝时的提示文本

* @param str

*/

public static void setDenyPermissionMessage(String str){

CalendarHelper.setDenyPermissionMessage(str);

}

相关推荐

【国窖白酒】国窖白酒报价
365体育APP官网

【国窖白酒】国窖白酒报价

⌛ 02-17 👁️ 5407
弹唱不求人,“扒谱”的十个基本步骤
365allsports

弹唱不求人,“扒谱”的十个基本步骤

⌛ 10-19 👁️ 224
异地外卖教程:如何给朋友点餐
365体育APP官网

异地外卖教程:如何给朋友点餐

⌛ 11-27 👁️ 5674
excel如何清除格式?简单几步快速恢复原始表格样式教程
抖音匿名连线怎么设置?抖音为什么找不到匿名申请连线?
泄的多音字组词
365bet中文

泄的多音字组词

⌛ 09-12 👁️ 286
《轩辕传奇》手游攻略指南
365allsports

《轩辕传奇》手游攻略指南

⌛ 12-17 👁️ 7307
【最新Sharp(夏普)手机大全】最新Sharp(夏普)手机报价及图片大全
呟是什么意思呟的解释 呟怎么读
365bet中文

呟是什么意思呟的解释 呟怎么读

⌛ 10-27 👁️ 6455