create-expo-module scaffolds a local module, one that lives in the app's modules/ folder rather than in its own npm 2,036 package. Its flags answer the prompts, so the command runs unattended:
npx create-expo-module@latest booknest-device --local --name BookNestDevice \
--package expo.modules.booknestdevice -p android apple \
--features Constant Function AsyncFunction --description "Device facts for BookNest"The local module will be created in modules/booknest-device directory. ✔ Downloaded module template from npm registry. ✔ Created the module from template files ✅ Successfully created Expo module in modules/booknest-device
It wrote Kotlin and Swift modules, a Gradle 19,597 file and expo-module.config.json, which names the classes to autolink. Replacing the template's sample functions with BookNest's gives:
class BookNestDeviceModule : Module() {
private val context: Context
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
override fun definition() = ModuleDefinition {
Name("BookNestDevice")
Constant("sdkInt") { Build.VERSION.SDK_INT } // computed once
Function("freeSpaceMb") { // synchronous
StatFs(context.filesDir.path).availableBytes / (1024 * 1024)
}
AsyncFunction("isPowerSaveModeAsync") { // runs off the JS thread
context.getSystemService(PowerManager::class.java).isPowerSaveMode
}The JavaScript side, src/BookNestDeviceModule.ts, declares a class with sdkInt: number, freeSpaceMb(): number and isPowerSaveModeAsync(): Promise<boolean>, and exports requireNativeModule<BookNestDeviceModule>('BookNestDevice'), a lookup by the Name() above. There is no Codegen, so that declaration is a promise you keep by hand. After a rebuild, the demo screen logged:
LOG API 36, 8819 MB free LOG power saver: false
No MainApplication.kt edit and no plugin: autolinking found expo-module.config.json in modules/.