flutter对android的日历数据相关操作

系统日历

三个不同URL的作用
  1. 每个url通过contentProvider能获得对应数据库的访问句柄,所以可以理解三个url对应三个数据库,如果通过一个事件关联3个库呢,下面会详细介绍。
    数据库介绍参考链接
//对系统日历插入行程事件的url
private static String CALANDER_EVENT_URL = "content://com.android.calendar/events";
//此表储存日历特定信息。 此表中的每一行都包含一个日历的详细信息,例如名称、颜色、同步信息等。
    private static String CALANDER_URL = "content://com.android.calendar/calendars";
//为日历中的行程事件添加提醒功能,就是通过系统通知栏告知你今天有什么行程    
private static String CALENDER_REMINDER_URL = "content://com.android.calendar/reminders";
同个事件关联不同表

这里以关联行程事件表事件提醒表为例子进行说明

  1. 使用为uri: content://com.android.calendar/events,日历插入一个行程事件,使用ContentProvider进行数据库插入数据时,方法会返回一个Uri。如果插入失败,这个Uri为空;如果成功,则不为空。
ContentValues event = new ContentValues();
            //事件的起始时间
            event.put("dtstart", startDateMis);
            if (cyclerType == 0) {
                    //如果不是循环事件,添加事件的结束事件
                    event.put("dtend", endDateMis);
              } else {
                    //如果是循环事件,添加持续事件
                    long durationSecondTime = (endDateMis - startDateMis) / 1000;
                    event.put(CalendarContract.Events.DURATION, String.format("P%dS", durationSecondTime));
            }
            //日历id,必须要有,可以通过**CALANDER_URL**查询获取其id
            event.put("calendar_id", calId);
            event.put("title", title);
            event.put("description", note);
            event.put("hasAlarm", 1);
            event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());//这个是时区,必须有
//这里的URL是event_url,别看错了
Uri events = activity.getContentResolver().insert(Uri.parse(CALANDER_EVENT_URL), event);
  1. 等待insert插入数据后,拿到Uri,使用uri:content://com.android.calendar/reminders,为我们的行程事件添加一个事件提醒功能,下面我们就可以开始把当前的数据的id关联到事件提醒功能表单中。
    注意:关键代码ContentUris.parseId(Uri uri),将Uri转成关联表的id。
//重新生成一个ContentValues对象,用于插入 事件提醒功能 的表单中
ContentValues values = new ContentValues();
//将上面insert插入数据生成的uri转成id,再塞到 事件提醒功能 的表单作为关联id
values.put(CalendarContract.Reminders.EVENT_ID, ContentUris.parseId(events));
//提前到什么时候进行提示
values.put(CalendarContract.Reminders.MINUTES, 15);
//提醒的方式            
values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
Uri uri = activity.getContentResolver().insert(Uri.parse(CALENDER_REMINDER_URL), values);
  1. 到这里为止,我们就成功的为系统日历添加上event
如何获取android日历读取权限
  1. 这篇文章重点不在于讲解flutter如何与native通信,如果想看的可以连接下Registrar类与Channel类,大概是内存块映射关系。我会抽时间总结下如何通信这块再出一篇文章。
  2. 着重讲下权限问题,因为在android 6.0以上日历读写权限是需要动态申请的。下面就是flutter层如何申请android权限的问题。
第一步

在android目录的mainfest文件写入需要的权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="xxxxxxxxx">
    //读日历数据
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    //写日历数据
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
</manifest>
第二步

在android代码中判断sdk版本,大于6.0动态申请权限

//REQUEST_CALENDAR_PERMISSION是requestCode,用来判断用户是否点击允许该权限了
public static int REQUEST_CALENDAR_PERMISSION = 10;
//ActivityCompat为androidx的包
requestCalendarAuthorization () {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_CALENDAR,
                Manifest.permission.READ_CALENDAR}, REQUEST_CALENDAR_PERMISSION);
        } else {
            result.success(1)
      }
}
第三步
  1. 为flutter注册方法映射入口,静态注册入口。permissions为映射句柄的名字。
    问题:在这一步卡了很久,因为动态获取权限乃是要在onRequestPermissionsResult方法中才能知道用户是否点击了允许。但是我又不在不能拿到完全的activity,怎么能实现这个方法呢。后面才知道google官网已经把一切都考虑很全面了。查看Registrar类可以看到能添加各种各样的回调用来响应原生层的方法。
        //android层面
       @JvmStatic
        fun registerWith(registrar: Registrar) {
            mContext = registrar.context()
            mActivity = registrar.activity()
            val channel = MethodChannel(registrar.messenger(), "permissions")
            //设置映射方法调用的回调,A类是实现MethodCallHandler方法的类
            channel.setMethodCallHandler(A())
            //设置动态获取权限的结果回调。
            registrar.addRequestPermissionsResultListener { id, permissions, grantResults ->
                //这里要注意通过grantResults来判断用户是同意还是拒绝权限
                return if (requestCode == REQUEST_CALENDAR_PERMISSION && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                      mCurrentResult?.success(1)
                      mCurrentResult = null
                      true
            } else {
                      mCurrentResult?.success(0)
                      mCurrentResult = null
                      false
                      }
                }
         }

        //当映射的方法调用时候,就能在onMethodCall找到相应方法;
         //call:方法名   result:用于把结果回调给flutter
            override fun onMethodCall(call: MethodCall, result: Result) {
        when {
            call.method == "requestPermission" -> {
                //记录当前方法的result引用,用于等待权限结果回来时候回调给flutter
                mCurrentResult = result
                //第二步的方法
                requestCalendarAuthorization()
            }
            ……
        }
    }
  1. flutter层调用
//生命调用的句柄:permissions
static const MethodChannel _channel = const MethodChannel('permissions');
//直接映射方法名,这里的result就会收到0 or 1
var result = await _channel.invokeMethod('requestPermission');

问题

  1. 如何能拿到Activity的onRequestPermissionsResult方法呢?
    解决办法:通过Registrar类添加listener
  2. 不在mainfest里面声明权限,只是代码动态获取,然后没有弹窗让用户选择是否允许。就是在《如何获取android日历读取权限-第一步》我跳过了,直接从第二步开始,没有权限弹窗出现。
    解决办法:把第一步加上,重新跑就可以了。好像是mainfest里面如果不声明权限的话,你手机-应用权限管理:看不到日历权限这一个开关的。所以自然也不会弹窗让用户选择是否允许打开。
  3. 添加无限循环事件失败,日历中只循环3次就不出现日程了。
    解决办法:在插入Event事件时候要区分是否是循环事件,如果是循环事件则不要tend,需要duration参数。rrule和rdate二选一即可,但是循环事件必须要duration参数,不需要tend。参考链接
//startTime起始时间,endTime终止时间。cyclerType日程事件类型
……
if (cyclerType == 0) {
            //如果不是循环事件
            event.put("dtend", endDateMis);
        } else {
            //如果是循环事件
            long durationSecondTime = (endDateMis - startDateMis) / 1000;
            event.put(CalendarContract.Events.DURATION, String.format("P%dS", durationSecondTime));
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容