如何使用 AppleScript 告诉我的设备当前与某个位置的距离?
How can I tell my devices current distance from a location using AppleScript?
基于此解决方案:,我正在尝试使用 CLLocation 的距离方法创建一个简单的地理围栏脚本(根据与特定位置的距离设置我的状态)。
我不是 AppleScript 专业人士,所以我在思考如何在脚本中初始化 CLLocation 对象(带有纬度和经度)以与原始答案脚本返回的我的当前位置进行比较。
所以我正在寻找这样的东西,其中 myCurrentLocation 是从原始脚本返回的位置对象(显然是错误的,只是一些伪 obj-c 的东西):
set tagetLatitude to "50.850206"
set targetLongitude to "5.690947"
set targetLocation to CLLocation's initWithLatitude:tagetLatitude longitude:targetLongitude
set distance to targetLocation's distance:myCurrentLocation
return distance
这是CJK的原稿供参考:
use framework "CoreLocation"
use framework "Foundation"
use scripting additions
property this : a reference to the current application
property nil : a reference to missing value
property _1 : a reference to reference
property CLLocationManager : a reference to CLLocationManager of this
property kCLLocationAccuracyThreeKilometers : a reference to 3000.0
--------------------------------------------------------------------------------
property running : false
property result : missing value -- Lat./long. or error description
property number : 0 -- Error code
property seconds : 10 -- Maximum time to allow script to run
--------------------------------------------------------------------------------
# IMPLEMENTATION:
my performSelectorOnMainThread:"getLocation" withObject:nil waitUntilDone:true
return my result
--------------------------------------------------------------------------------
# HANDLERS & SCRIPT OBJECTS:
to getLocation()
set locationManager to CLLocationManager's new()
locationManager's setDelegate:me
locationManager's setDesiredAccuracy:kCLLocationAccuracyThreeKilometers
set my running to true
set started to current date
locationManager's startUpdatingLocation()
repeat while my running
delay 0.5
if (current date) - started > my seconds then exit repeat
end repeat
end getLocation
on locationManager:locationManager didUpdateLocations:locations
local locationManager, locations
locationManager's stopUpdatingLocation()
set my running to false
set my result to (locations's valueForKey:"coordinate") as record
end locationManager:didUpdateLocations:
on locationManager:locationManager didFailWithError:err
local locationManager, err
tell err's code()
set my number to it
set my result to item (it + 1) in my enum's kCLError
if it ≠ 0 then set my running to false
end tell
end locationManager:didFailWithError:
script enum
property kCLError : {¬
"Location Unknown", ¬
"Denied", ¬
"Network", ¬
"Heading Failure", ¬
"Region Monitoring Denied", ¬
"Region Monitoring Failure", ¬
"Region Monitoring Setup Delayed", ¬
"Region Monitoring Response Delayed", ¬
"Geocode Found No Result", ¬
"Geocode Found Partial Result", ¬
"Geocode Canceled", ¬
"Deferred Failed", ¬
"Deferred Not Updating Location", ¬
"Deferred Accuracy Too Low", ¬
"Deferred Distance Filtered", ¬
"Deferred Canceled", ¬
"Ranging Unavailable", ¬
"Ranging Failure"}
property CLAuthorizationStatus : {¬
"Not Determined", ¬
"Restricted", ¬
"Denied", ¬
"Authorized (Always)", ¬
"Authorized When In Use"}
end script
---------------------------------------------------------------------------❮END❯
其实你已经不远了:
on distance to {latitude:||, longitude:|λ|}
((my location)'s distanceFromLocation:(CLLocation's ¬
alloc()'s initWithLatitude:|| longitude:|λ|)) ¬
as real
end distance
其中 my location
是 CLLocation
的实例。因此,在原始脚本中,而不是:
set my result to (locations's valueForKey:"coordinate")
你想要:
set my result to item 1 in locations
因为 locations
应该是 CLLocation
值的 NSArray
。
但是,自从编写该脚本后,CLLocationManager
class 中添加了一个新的实例方法,即 requestLocation()
因此,脚本可能会缩短为如下所示:
--------------------------------------------------------------------------------
use framework "Foundation"
use framework "CoreLocation"
--------------------------------------------------------------------------------
property this : a reference to current application
property nil : a reference to missing value
property CLLocation : a reference to CLLocation of this
property CLLocationManager : a reference to CLLocationManager of this
--------------------------------------------------------------------------------
property location : []
--------------------------------------------------------------------------------
# IMPLEMENTATION:
my performSelectorOnMainThread:"findMe" withObject:nil waitUntilDone:yes
return the distance to {latitude:-90.0, longitude:0.0}
to findMe()
tell CLLocationManager's new()
setDelegate_(me)
setDesiredAccuracy_(3000.0)
requestLocation()
end tell
repeat until my location ≠ []
delay 1
end repeat
end findMe
--------------------------------------------------------------------------------
# MAIN HANDLERS:
on distance from A as {record, reference} : [] to B as {record, reference}
local A, B
if A = [] then set A to my location
if A's class = record then
set {latitude:||, longitude:|λ|} to A
tell CLLocation's alloc() to set A to ¬
initWithLatitude_longitude_(||, |λ|)
end if
if B's class = record then
set {latitude:||, longitude:|λ|} to B
tell CLLocation's alloc() to set B to ¬
initWithLatitude_longitude_(||, |λ|)
end if
(B's distanceFromLocation:A) as meters as kilometers
end distance
--------------------------------------------------------------------------------
# DELEGATED HANDLERS:
on locationManager:[] didUpdateLocations:here
set [my location] to here
end locationManager:didUpdateLocations:
on locationManager:[] didFailWithError:E
error E's localizedDescription() as text
end locationManager:didFailWithError:
---------------------------------------------------------------------------❮END❯
我还没有测试这个脚本,因为我在 High Sierra,它需要 Mojave 或更高版本。我会在某个时候重新启动到 Catalina 并检查它是否有错误。
基于此解决方案:
我不是 AppleScript 专业人士,所以我在思考如何在脚本中初始化 CLLocation 对象(带有纬度和经度)以与原始答案脚本返回的我的当前位置进行比较。
所以我正在寻找这样的东西,其中 myCurrentLocation 是从原始脚本返回的位置对象(显然是错误的,只是一些伪 obj-c 的东西):
set tagetLatitude to "50.850206"
set targetLongitude to "5.690947"
set targetLocation to CLLocation's initWithLatitude:tagetLatitude longitude:targetLongitude
set distance to targetLocation's distance:myCurrentLocation
return distance
这是CJK的原稿供参考:
use framework "CoreLocation"
use framework "Foundation"
use scripting additions
property this : a reference to the current application
property nil : a reference to missing value
property _1 : a reference to reference
property CLLocationManager : a reference to CLLocationManager of this
property kCLLocationAccuracyThreeKilometers : a reference to 3000.0
--------------------------------------------------------------------------------
property running : false
property result : missing value -- Lat./long. or error description
property number : 0 -- Error code
property seconds : 10 -- Maximum time to allow script to run
--------------------------------------------------------------------------------
# IMPLEMENTATION:
my performSelectorOnMainThread:"getLocation" withObject:nil waitUntilDone:true
return my result
--------------------------------------------------------------------------------
# HANDLERS & SCRIPT OBJECTS:
to getLocation()
set locationManager to CLLocationManager's new()
locationManager's setDelegate:me
locationManager's setDesiredAccuracy:kCLLocationAccuracyThreeKilometers
set my running to true
set started to current date
locationManager's startUpdatingLocation()
repeat while my running
delay 0.5
if (current date) - started > my seconds then exit repeat
end repeat
end getLocation
on locationManager:locationManager didUpdateLocations:locations
local locationManager, locations
locationManager's stopUpdatingLocation()
set my running to false
set my result to (locations's valueForKey:"coordinate") as record
end locationManager:didUpdateLocations:
on locationManager:locationManager didFailWithError:err
local locationManager, err
tell err's code()
set my number to it
set my result to item (it + 1) in my enum's kCLError
if it ≠ 0 then set my running to false
end tell
end locationManager:didFailWithError:
script enum
property kCLError : {¬
"Location Unknown", ¬
"Denied", ¬
"Network", ¬
"Heading Failure", ¬
"Region Monitoring Denied", ¬
"Region Monitoring Failure", ¬
"Region Monitoring Setup Delayed", ¬
"Region Monitoring Response Delayed", ¬
"Geocode Found No Result", ¬
"Geocode Found Partial Result", ¬
"Geocode Canceled", ¬
"Deferred Failed", ¬
"Deferred Not Updating Location", ¬
"Deferred Accuracy Too Low", ¬
"Deferred Distance Filtered", ¬
"Deferred Canceled", ¬
"Ranging Unavailable", ¬
"Ranging Failure"}
property CLAuthorizationStatus : {¬
"Not Determined", ¬
"Restricted", ¬
"Denied", ¬
"Authorized (Always)", ¬
"Authorized When In Use"}
end script
---------------------------------------------------------------------------❮END❯
其实你已经不远了:
on distance to {latitude:||, longitude:|λ|}
((my location)'s distanceFromLocation:(CLLocation's ¬
alloc()'s initWithLatitude:|| longitude:|λ|)) ¬
as real
end distance
其中 my location
是 CLLocation
的实例。因此,在原始脚本中,而不是:
set my result to (locations's valueForKey:"coordinate")
你想要:
set my result to item 1 in locations
因为 locations
应该是 CLLocation
值的 NSArray
。
但是,自从编写该脚本后,CLLocationManager
class 中添加了一个新的实例方法,即 requestLocation()
因此,脚本可能会缩短为如下所示:
--------------------------------------------------------------------------------
use framework "Foundation"
use framework "CoreLocation"
--------------------------------------------------------------------------------
property this : a reference to current application
property nil : a reference to missing value
property CLLocation : a reference to CLLocation of this
property CLLocationManager : a reference to CLLocationManager of this
--------------------------------------------------------------------------------
property location : []
--------------------------------------------------------------------------------
# IMPLEMENTATION:
my performSelectorOnMainThread:"findMe" withObject:nil waitUntilDone:yes
return the distance to {latitude:-90.0, longitude:0.0}
to findMe()
tell CLLocationManager's new()
setDelegate_(me)
setDesiredAccuracy_(3000.0)
requestLocation()
end tell
repeat until my location ≠ []
delay 1
end repeat
end findMe
--------------------------------------------------------------------------------
# MAIN HANDLERS:
on distance from A as {record, reference} : [] to B as {record, reference}
local A, B
if A = [] then set A to my location
if A's class = record then
set {latitude:||, longitude:|λ|} to A
tell CLLocation's alloc() to set A to ¬
initWithLatitude_longitude_(||, |λ|)
end if
if B's class = record then
set {latitude:||, longitude:|λ|} to B
tell CLLocation's alloc() to set B to ¬
initWithLatitude_longitude_(||, |λ|)
end if
(B's distanceFromLocation:A) as meters as kilometers
end distance
--------------------------------------------------------------------------------
# DELEGATED HANDLERS:
on locationManager:[] didUpdateLocations:here
set [my location] to here
end locationManager:didUpdateLocations:
on locationManager:[] didFailWithError:E
error E's localizedDescription() as text
end locationManager:didFailWithError:
---------------------------------------------------------------------------❮END❯
我还没有测试这个脚本,因为我在 High Sierra,它需要 Mojave 或更高版本。我会在某个时候重新启动到 Catalina 并检查它是否有错误。