Skip to content
Lucent
SEARCH LUCENT

Search guides, APIs, and examples.

GitHub

Very early and experimental. The language, the generated native code and every package API change without notice. Do not use Lucent in production.

5. Read the position from iOS and Android

One module that calls CoreLocation on iOS and LocationManager on Android.

location.lucent.ts
import { PLATFORM } from "lucent:platform";
import { CLLocation, CLLocationManager } from "lucent:ios/CoreLocation";
import { Location, LocationManager } from "lucent:android/android.location";
import { appContext } from "lucent:android";
import { main } from "lucent:thread";
import type { Fix } from "./trip.lucent";
// --- iOS ---------------------------------------------------------------------
function fromCLLocation(location: CLLocation): Fix {
const c = location.coordinate;
return { latitude: c.latitude, longitude: c.longitude, time: location.timestamp.getTime() };
}
// --- Android -----------------------------------------------------------------
function fromLocation(location: Location): Fix {
return {
latitude: location.getLatitude(),
longitude: location.getLongitude(),
time: Number(location.getTime()),
};
}
// --- The module --------------------------------------------------------------
/** The last position the device knows, without waiting for a new one. */
export async function lastFix(): Promise<Fix | null> {
if (PLATFORM === "ios") {
const location = await main(() => new CLLocationManager().location);
return location ? fromCLLocation(location) : null;
} else {
const manager = appContext().getSystemService(LocationManager);
const location = manager?.getLastKnownLocation(LocationManager.GPS_PROVIDER) ?? null;
return location ? fromLocation(location) : null;
}
}
See the C++
m_location.mm
// Generated by Lucent from location.lucent.ts. Do not edit.
#import <CoreLocation/CoreLocation.h>
#import <_LocationEssentials/LocationEssentials.h>
#include <lucent/platform/ios.h>
#include "m_location.h"
#pragma push_macro("c")
#undef c
#pragma push_macro("fromCLLocation")
#undef fromCLLocation
#pragma push_macro("lastFix")
#undef lastFix
#pragma push_macro("latitude")
#undef latitude
#pragma push_macro("location")
#undef location
#pragma push_macro("longitude")
#undef longitude
#pragma push_macro("time")
#undef time
namespace lucent_app {
lucent::Ref<lucent_app::S_Fix> m_location::fromCLLocation(lucent::NativeRef p0_) {
#line 11 "location.lucent.ts"
lucent::Ref<lucent_app::S_CLLocationCoordinate2D> c = ({ auto s0_ = [((CLLocation*)lucent::objc::unwrap(p0_)) coordinate]; auto o0_ = std::make_shared<lucent_app::S_CLLocationCoordinate2D>(); o0_->latitude = static_cast<double>(s0_.latitude); o0_->longitude = static_cast<double>(s0_.longitude); o0_; });
#line 12 "location.lucent.ts"
double v3_ = c->latitude;
double v5_ = c->longitude;
lucent::Date v6_ = lucent::objc::fromNSDate([((CLLocation*)lucent::objc::unwrap(p0_)) timestamp], "CLLocation.timestamp");
double v7_ = v6_->getTime();
return ({ auto obj_3 = std::make_shared<lucent_app::S_Fix>(); obj_3->latitude = v3_; obj_3->longitude = v5_; obj_3->time = v7_; obj_3; });
}
lucent::Promise<lucent::Opt<lucent::Ref<lucent_app::S_Fix>>> m_location::lastFix() {
#line 29 "location.lucent.ts"
{
#line 30 "location.lucent.ts"
lucent::Fn<lucent::Opt<lucent::NativeRef>()> v0_ = lucent::Fn<lucent::Opt<lucent::NativeRef>()>([]() mutable -> lucent::Opt<lucent::NativeRef> {
#line 30 "location.lucent.ts"
lucent::NativeRef v0_ = lucent::objc::wrap([[CLLocationManager alloc] init], "new CLLocationManager");
return lucent::objc::wrapOpt([((CLLocationManager*)lucent::objc::unwrap(v0_)) location]);
});
#line 30 "location.lucent.ts"
lucent::Promise<lucent::Opt<lucent::NativeRef>> v1_ = lucent::runOnMain(v0_);
lucent::Opt<lucent::NativeRef> v2_ = co_await v1_;
lucent::Opt<lucent::NativeRef> location = std::move(v2_);
#line 31 "location.lucent.ts"
bool v4_ = lucent::truthy(location);
lucent::Opt<lucent::Ref<lucent_app::S_Fix>> v11_{};
if (v4_) {
lucent::Ref<lucent_app::S_Fix> v7_ = lucent_app::m_location::fromCLLocation(location.value());
v11_ = lucent::Opt<lucent::Ref<lucent_app::S_Fix>>(v7_);
} else {
v11_ = lucent::Opt<lucent::Ref<lucent_app::S_Fix>>(lucent::null);
}
#line 31 "location.lucent.ts"
co_return v11_;
}
}
void m_location::init() {
}
} // namespace lucent_app
#pragma pop_macro("time")
#pragma pop_macro("longitude")
#pragma pop_macro("location")
#pragma pop_macro("latitude")
#pragma pop_macro("lastFix")
#pragma pop_macro("fromCLLocation")
#pragma pop_macro("c")

One module holds both platforms. Inside if (PLATFORM === "ios"), the code uses CoreLocation; in the else, Android's LocationManager. Each platform's build compiles only its own branch.

  • fromCLLocation uses an iOS type, so it's iOS code and compiles only for iOS. fromLocation is Android code.
  • CLLocationManager is main-thread only on iOS, so it's made inside main(). Its result, a CLLocation, comes back as a promise.
  • Both branches turn SDK objects into a Fix before returning. SDK objects can't cross to JavaScript.
  • import type { Fix } shares the type with the trip module.
  • Java's getTime() returns a long, which Lucent gives as a bigint. Milliseconds since 1970 fit in a number, so Number() makes the Fix field one.

Android uses the platform's LocationManager, not Play services' fused provider, which the app doesn't include.

Rebuild the app. On a simulator or emulator with a location set, the screen adds where you are.

Without a permission, iOS has no position to give, and Android throws a java.lang.SecurityException error, whose message the screen shows. Step 7 asks for the permission.