Archive for the 'EKStructuredLocation' Category

2015/09/25 Remindersのイベントに場所(geofence alarm)を追加する(OS X 10.11版)

Reminders.app(日本語名:リマインダー)の指定イベントに場所(geofence alarm)を追加するAppleScriptのEl Capitan(OS X 10.11)版です。

Yosemite(OS X 10.10.x)のScript Editor上では実行はおろか構文確認(コンパイル)もできないのでご注意ください。

El Capitanのリリースノートで「バグ修正」項目として紹介されている内容の1つで・・・Cocoaの各APIでの定数をAppleScriptにBridgeするようになった、という項目のテスト用にOS X 10.11上で一部修正してみました。

OS X 10.10.x上では、こうした定数があったら、

enums.png

最初の項目が0で、次が1で・・・とあたりをつけて数値で指定するとか、Xcode上でヘッダーファイルを確認して実際の値を調べる・・・という不毛な作業が必要だったわけですが、それがEl Capitanでは解消されるということです。

ただ、目下AppleScriptのプログラムリストの中で、「変数およびサブルーチン名」として色分けされる項目が、とくにCocoaの機能を使うようになってからというもの増えすぎており、可読性が落ちているので、なんとかしてほしいところです。

ちなみに、ASObjC Explorer 4ではこの問題を軽減しており、「サブルーチン名」と「Cocoaのメソッド名」については変数名とは色分けするようになっています(El Capitan上で比較のためにスクリーンショットを撮りましたが、掲載してはいけないことに気づいて削除)。

AppleScript名:Remindersのイベントに場所(geofence alarm)を追加する_10.11
– Created 2014-12-08 by Shane Stanley
– Modified 2015-09-24 by Takaaki Naganoya –Geofence Alarm
– Modified 2015-09-24 by Shane Stanley –Fix the way to Create the geofence alarm
– Modified 2015-09-24 by Takaaki Naganoya –change and test for El Capitan’s Enum bridging

–Reference:
–http://stackoverflow.com/questions/26903847/add-location-to-ekevent-ios-calendar
–http://timhibbard.com/blog/2013/01/03/how-to-create-remove-and-manage-geofence-reminders-in-ios-programmatically-with-xcode/

use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “EventKit”

–Fetch an event to add geofence alarm
tell application “Reminders”
  tell account “iCloud”
    tell list “ホーム” –Use “Home” in English environment or your favorite one
      set theID to id of (last reminder whose completed is false)
    end tell
  end tell
end tell

set theID to text 20 thru -1 of theID

setLocationToLeaveForReminderID(35.745769, 139.675565, “ゲームシティ板橋”, theID, 200)

–指定場所に到着した時に発動するGeofence Alarmを指定のリマインダーに登録する。Geofence半径指定つき(単位:メートル)
on setLocationToEnterForReminderID(aLatitude, aLongitude, aTitle, theID, aRangeByMeter)
  – Get event store
  
set eventStore to current application’s EKEventStore’s alloc()’s initWithAccessToEntityTypes:(current application’s EKEntityMaskReminder)
  
– Get the reminder
  
set theReminder to eventStore’s calendarItemWithIdentifier:theID
  
–Create the geofence alarm
  
set enterAlarm to current application’s EKAlarm’s alarmWithRelativeOffset:0
  
enterAlarm’s setProximity:(current application’s EKAlarmProximityEnter)
  
set structLoc to current application’s EKStructuredLocation’s locationWithTitle:aTitle
  
set aLoc to current application’s CLLocation’s alloc()’s initWithLatitude:aLatitude longitude:aLongitude
  
structLoc’s setGeoLocation:aLoc
  
  
– Set radius by meters
  
structLoc’s setRadius:aRangeByMeter
  
enterAlarm’s setStructuredLocation:structLoc
  
  
theReminder’s addAlarm:enterAlarm
  
set aRes to eventStore’s saveReminder:theReminder commit:true |error|:(missing value)
  
  
return aRes as boolean
end setLocationToEnterForReminderID

–指定場所を出発した時に発動するGeofence Alarmを指定のリマインダーに登録する。Geofence半径指定つき(単位:メートル)
on setLocationToLeaveForReminderID(aLatitude, aLongitude, aTitle, theID, aRangeByMeter)
  – Get event store; 1 means reminders
  
set eventStore to current application’s EKEventStore’s alloc()’s initWithAccessToEntityTypes:(current application’s EKEntityMaskReminder)
  
– Get the reminder
  
set theReminder to eventStore’s calendarItemWithIdentifier:theID
  
–Create the geofence alarm
  
set leaveAlarm to current application’s EKAlarm’s alarmWithRelativeOffset:0
  
leaveAlarm’s setProximity:(current application’s EKAlarmProximityLeave)
  
set structLoc to current application’s EKStructuredLocation’s locationWithTitle:aTitle
  
set aLoc to current application’s CLLocation’s alloc()’s initWithLatitude:aLatitude longitude:aLongitude
  
structLoc’s setGeoLocation:aLoc
  
  
– Set radius by meters
  
structLoc’s setRadius:aRangeByMeter
  
leaveAlarm’s setStructuredLocation:structLoc
  
  
theReminder’s addAlarm:leaveAlarm
  
set aRes to eventStore’s saveReminder:theReminder commit:true |error|:(missing value)
  
  
return aRes as boolean
end setLocationToLeaveForReminderID

★Click Here to Open This Script 

2015/09/24 Remindersのイベントに場所(geofence alarm)を追加する

Reminders.app(日本語名:リマインダー)の指定イベントに場所(geofence alarm)を追加するAppleScriptです。

リマインダーのAppleScript用語辞書では「場所」についてはまったくサポート機能が用意されておらず(El CapitanのRemindersでもサポートなし)、全世界のScripterが肩を落としたものでした(Apple純正アプリのAppleScript用語辞書の残念さは本当に残念です。Finderのタグなど登場して相当の時間が経っているのに機能が追加されていません。タグについてはASOCで直接操作できるので、Appleの対応をもはや期待していない昨今)。

rem5.png
▲リマインダー(Reminders.app)のAppleScript用語辞書にはLocation関連の機能はない

そこで、出来のよくないリマインダーをアテにせず、Cocoaの機能を呼び出して、AppleScriptだけで「場所」の情報を追加するAppleScriptを書いてみました(Shane Stanleyの添削済み)。

この「場所」については、若干の説明が必要です。

geofence.png

緯度・経度でピンポイントの場所を指定できますが、ピンポイントすぎるのと誤差を許容するため「だいたいこのあたり」といった範囲の指定が必要になります。これを「Geofence」と呼ぶようです。

このピンポイントの場所から「半径XXXXメートル以内」のGeofenceに入った場合のアラーム(Enter Alarm)と、出た場合のアラーム(Leave Alarm)の2種類のうちどちらかを設定できるとのこと。

逆に、入るとか出るとかいうアクション指定のないものも作れますが、これがどういう挙動をするのかいまひとつ分かりません(Geofence内でずっと何かの通知が出る?)。

rem1.png
▲テスト用に作ったリマインダー項目

rem2.png
▲初期状態では何も「場所」関連の情報はついていません

rem3.png
▲本Script実行後の状態

rem4.png
▲内容を確認すると、意図したとおり「ゲームシティ板橋」のGeofenceが追加

img_2822_resized.png
▲ゲームシティ板橋店

AppleScript名:Remindersのイベントに場所(geofence alarm)を追加する
– Created 2014-12-08 by Shane Stanley
– Modified 2015-09-24 by Takaaki Naganoya
– Modified 2015-09-24 by Shane Stanley

–Reference:
–http://stackoverflow.com/questions/26903847/add-location-to-ekevent-ios-calendar
–http://timhibbard.com/blog/2013/01/03/how-to-create-remove-and-manage-geofence-reminders-in-ios-programmatically-with-xcode/

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “EventKit”

–Fetch an event to add geofence alarm
tell application “Reminders”
  tell account “iCloud”
    tell list “ホーム” –Use “Home” in English environment or your favorite one
      set theID to id of (last reminder whose completed is false)
      
–>  ”x-apple-reminder://868467FD-1F90-47EF-A9B1-A39334341D41″
    end tell
  end tell
end tell

set theID to text 20 thru -1 of theID
–> “868467FD-1F90-47EF-A9B1-A39334341D41″

setLocationToEnterForReminderID(35.745769, 139.675565, “ゲームシティ板橋”, theID, 200)

on setLocationToEnterForReminderID(aLatitude, aLongitude, aTitle, theID, aRangeByMeter)
  – Get event store; 1 means reminders
  
set eventStore to current application’s EKEventStore’s alloc()’s initWithAccessToEntityTypes:2 –Deprecated in OS X 10.9 ?
  
(* Enums: { EKEntityMaskEvent:1, EKEntityMaskReminder:2} *)
  
  
– Get the reminder
  
set theReminder to eventStore’s calendarItemWithIdentifier:theID
  
  
–Create the geofence alarm
  
set enterAlarm to current application’s EKAlarm’s alarmWithRelativeOffset:0 –ここがキモ
  
  
enterAlarm’s setProximity:1 – EKAlarmProximityEnter
  
(* Enums: { EKAlarmProximityNone:0, EKAlarmProximityEnter:1, EKAlarmProximityLeave:2 } *)
  
  
set structLoc to current application’s EKStructuredLocation’s locationWithTitle:aTitle
  
set aLoc to current application’s CLLocation’s alloc()’s initWithLatitude:aLatitude longitude:aLongitude
  
structLoc’s setGeoLocation:aLoc
  
  
– Set radius by meters
  
structLoc’s setRadius:aRangeByMeter –by meters
  
enterAlarm’s setStructuredLocation:structLoc
  
  
theReminder’s addAlarm:enterAlarm
  
set aRes to eventStore’s saveReminder:theReminder commit:true |error|:(missing value)
  
  
return aRes as boolean
end setLocationToEnterForReminderID

on setLocationToLeaveForReminderID(aLatitude, aLongitude, aTitle, theID, aRangeByMeter)
  – Get event store; 1 means reminders
  
set eventStore to current application’s EKEventStore’s alloc()’s initWithAccessToEntityTypes:2 –Deprecated in OS X 10.9 ?
  
(* Enums: { EKEntityMaskEvent:1, EKEntityMaskReminder:2} *)
  
  
– Get the reminder
  
set theReminder to eventStore’s calendarItemWithIdentifier:theID
  
  
–Create the geofence alarm
  
set enterAlarm to current application’s EKAlarm’s alarmWithRelativeOffset:0 –ここがキモ
  
  
enterAlarm’s setProximity:2 – EKAlarmProximityLeave
  
(* Enums: { EKAlarmProximityNone:0, EKAlarmProximityEnter:1, EKAlarmProximityLeave:2 } *)
  
  
set structLoc to current application’s EKStructuredLocation’s locationWithTitle:aTitle
  
set aLoc to current application’s CLLocation’s alloc()’s initWithLatitude:aLatitude longitude:aLongitude
  
structLoc’s setGeoLocation:aLoc
  
  
– Set radius by meters
  
structLoc’s setRadius:aRangeByMeter –by meters
  
enterAlarm’s setStructuredLocation:structLoc
  
  
theReminder’s addAlarm:enterAlarm
  
set aRes to eventStore’s saveReminder:theReminder commit:true |error|:(missing value)
  
  
return aRes as boolean
end setLocationToLeaveForReminderID

★Click Here to Open This Script