全自动化!安卓和苹果日程同步方案。

Yunxiao 2020年12月06日 667次浏览

前言

最近开始做日程管理,也就是在一天的开始大概规划一下一天需要做什么,然后到晚上在来看看完成的如何。通过几天的实操下来,发现确实在某种程度上提升了效率,大概是因为看到本来计划好的日程没完成心有愧疚吧。
那么由于我的主要移动设备是一部小米手机和ipad。之前一直用Ipad自带的提醒事项来提醒自己需要做的一些事,但是没法同步到手机上很痛苦。然后某天突然发现小米日历通过icloud账号来同步日历,不知道其他厂商的自带日历有没有实现这个功能,不过就算没有,网上也有用来专门同步icloud日历到安卓的软件。

小米日历同步icloud日历

这里以小米的自带日历为例子,流程如下:

  1. 开打小米日历
  2. 点击右上角的三个点
  3. 打开设置
  4. 打开日程导入
  5. 点击caldav账号导入
  6. 然后按照帮助指示去苹果官网获取一个app专用密码,这个密码就是用来在非apple官方的设备上登陆icloud账号。
  7. 在导入页面输入apple id 以及刚才生成的app专用密码,服务器一栏填写“icloud.com”
    通过上述操作,就能够同步icloud日历到小米日历了,此外,还可以设置同步频率以及手动同步等。
    不过实际使用下来还是有点坑,我的习惯实在负一屏直接通过日历组件看日程,但是这个日历组件并不会直接显示更新的信息,想在负一屏直接看到更新了的信息需要点进日历app里面,让它自动同步一下再返回就能看到了。
    最开始觉得有点鸡肋,不过用了一段时间也就习惯了,毕竟点一下也就几秒钟,加上看日程其实也不是什么高频动作,所以总的来说体验还行吧。

ipad提醒事项同步到日历

上面,我们把icloud日历同步到了小米日历。而且这个同步时双向的,其实以及满足很多人需求了。不过我并不喜欢用苹果自带的日历去分类创建日程,比起苹果的日历,我更喜欢用它的提醒事项,完成一件事后去提醒事项里勾掉是一件很爽的事。所以我就想看看有没有办法在提醒事项里创建日程然后同步到苹果的日历,然后苹果的日历再同步到我小米的日历,这不就舒服了吗。
果然,网上就有解决方案,是通过快捷指令的自动化来实现的,需要一段javascript的脚本。
https://zhuanlan.zhihu.com/p/169566930
这是知乎上的原文,下面我搬运下这个实现的步骤。

实现步骤

提前准备工作

向要同步提醒事项到日历,需要提醒事项中有和日历中相同的标签。也就是你在日历中创建的日历要和提醒事项中一一对应。比如学习,生活,工作分类。
image.png
这是提醒事项中的分类
image.png
这是日历里面的分类,需要和上面的对应起来

正式开始

下载scriptable,添加如下的一段javascript脚本

var dur_month = 1

const startDate = new Date()
startDate.setMonth(startDate.getMonth() - dur_month)
console.log(`日历的开始时间 ${startDate.toLocaleDateString()}`)

const endDate = new Date()
endDate.setMonth(endDate.getMonth() + dur_month)
console.log(`日历的结束时间 ${endDate.toLocaleDateString()}`)


const reminders = await Reminder.allDueBetween(startDate, endDate)
console.log(`获取 ${reminders.length} 条提醒事项`)

var calendar = await Calendar.forEvents()

//获取日历名和对应的日历
var m_dict = {}
for(cal of calendar)
{
   m_dict[cal.title] = cal
   //console.log(`日历:${cal.title}`)
}

const events = await CalendarEvent.between(startDate, endDate, calendar)
console.log(`获取 ${events.length} 条日历`)

for (const reminder of reminders) {
  //reminder的标识符
  const targetNote = `[Reminder] ${reminder.identifier}`
  const [targetEvent] = events.filter(e => e.notes != null && (e.notes.indexOf(targetNote) != -1))//过滤重复的reminder
  if(!m_dict[reminder.calendar.title])
  {
        console.warn("找不到日历"+ reminder.calendar.title)
        continue
  }
  if (targetEvent) {
    //console.log(`找到已经创建的事项 ${reminder.title}`)
    updateEvent(targetEvent, reminder)

  } else {
    console.warn(`创建事项 ${reminder.title} 到 ${reminder.calendar.title}`)
    const newEvent = new CalendarEvent()
    newEvent.notes = targetNote + "\n" + reminder.notes//要加入备注
    updateEvent(newEvent, reminder)

  }
}

Script.complete()

function updateEvent(event, reminder) {
  event.title = `${reminder.title}`
  cal_name = reminder.calendar.title
  cal = m_dict[cal_name]
  event.calendar = cal
  //console.warn(event.calendar.title)
  //已完成事项
  if(reminder.isCompleted)
  {
    event.title = `✅${reminder.title}`
    event.isAllDay = false
    event.startDate = reminder.completionDate
    var ending = new Date(reminder.completionDate)
    ending.setHours(ending.getHours()+1)
    event.endDate = ending
    
    var period = (reminder.dueDate-reminder.completionDate)/1000/3600/24
    period = period.toFixed(1)
    if(period < 0)
    {
      period = -period
      event.location = " 延期" + period + "天完成" 
    }
    else if (period == 0)
    {
      event.location = " 准时完成"
    }
    else
    {
       event.location = " 提前" + period + "天完成"
    }
  }
  //未完成事项
  else{
      const nowtime  = new Date()
      var period = (reminder.dueDate-nowtime)/1000/3600/24
      period = period.toFixed(1)
      //console.log(reminder.title+(period))
      if(period < 0)
      {
        //待办顺延

         event.location = " 延期" + (-period) + "天" 
         //如果不是在同一天,设置为全天事项
        if(reminder.dueDate.getDate() != nowtime.getDate())
        {
           event.title = `❌${reminder.title}` 
           event.startDate = nowtime
           event.endDate = nowtime
          event.isAllDay = true    
        }
        //在同一天的保持原来的时间
        else
        {
          event.title = `⭕️${reminder.title}`
          event.isAllDay = false  
          event.startDate = reminder.dueDate
          var ending = new Date(reminder.dueDate)
          ending.setHours(ending.getHours()+1)
          event.endDate = ending
        }
         console.log(`【${reminder.title}】待办顺延${-period}天` )
      }
      else
      {
         event.title = `⭕️${reminder.title}`
         event.isAllDay = false
         event.location = "还剩" + period + "天" 
         event.startDate = reminder.dueDate
         var ending = new Date(reminder.dueDate)
         ending.setHours(ending.getHours()+1)
         event.endDate = ending
      }
    }
  event.save()
}

打开ios自带的快捷指令app,创建一个自动化,在打开提醒事项或者日历的时候自动运行scriptable的同步脚本文件,记得吧always run in app这个选项关闭
image.png

触发条件可以根据自己设置,原作者是设置当提醒事项和日历俩个App开关时都执行这个脚本,我根据自己的习惯变成了关闭提醒事项时运行。这样,我的日程同步完整流程就是:
打开提醒事项-->编写需要提醒-->返回桌面-->脚本自动运行同步日程到日历-->苹果日历自动同步到小米日历
而且这个作者还给每个日程前加上了表情来表示是否完成事项,完成后也会显示提前完成还是延时完成,过期的任务也会给你自动延期到第二天,总的来说体验还是可以

其他

如果想要三端同步其实也是可以的,win10自带的日历也可以同步icloud日历,不过不知道什么原因我的账号暂时添加不上去,而且我暂时也没这个需求,就没有去折腾,有兴趣的读者可以去开发更好玩更使用的同步流程。
以上。