diff --git a/components/settings.js b/components/settings.js
index dabad32..9373ec3 100644
--- a/components/settings.js
+++ b/components/settings.js
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { View, Text, TouchableOpacity, Linking } from "react-native";
-import * as ExpoFelicaReader from "expo-felica-reader";
+import * as ExpoFelicaReader from "../modules/expo-felica-reader/src";
import * as Updates from "expo-updates";
import StatusbarDetect from "../StatusbarDetect";
import { AS } from "../storageControl";
diff --git a/modules/expo-felica-reader/android/build.gradle b/modules/expo-felica-reader/android/build.gradle
new file mode 100644
index 0000000..888b263
--- /dev/null
+++ b/modules/expo-felica-reader/android/build.gradle
@@ -0,0 +1,92 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'maven-publish'
+
+group = 'expo.modules.felicareader'
+version = '0.2.0'
+
+buildscript {
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
+ if (expoModulesCorePlugin.exists()) {
+ apply from: expoModulesCorePlugin
+ applyKotlinExpoModulesCorePlugin()
+ }
+
+ // Simple helper that allows the root project to override versions declared by this library.
+ ext.safeExtGet = { prop, fallback ->
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+ }
+
+ // Ensures backward compatibility
+ ext.getKotlinVersion = {
+ if (ext.has("kotlinVersion")) {
+ ext.kotlinVersion()
+ } else {
+ ext.safeExtGet("kotlinVersion", "1.8.10")
+ }
+ }
+
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
+ }
+}
+
+afterEvaluate {
+ publishing {
+ publications {
+ release(MavenPublication) {
+ from components.release
+ }
+ }
+ repositories {
+ maven {
+ url = mavenLocal().url
+ }
+ }
+ }
+}
+
+android {
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
+
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
+ if (agpVersion.tokenize('.')[0].toInteger() < 8) {
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_17.majorVersion
+ }
+ }
+
+ namespace "expo.modules.felicareader"
+ defaultConfig {
+ minSdkVersion safeExtGet("minSdkVersion", 21)
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
+ versionCode 2
+ versionName "0.2.0"
+ }
+ lintOptions {
+ abortOnError false
+ }
+ publishing {
+ singleVariant("release") {
+ withSourcesJar()
+ }
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation project(':expo-modules-core')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
+}
diff --git a/modules/expo-felica-reader/android/src/main/AndroidManifest.xml b/modules/expo-felica-reader/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bdae66c
--- /dev/null
+++ b/modules/expo-felica-reader/android/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/modules/expo-felica-reader/android/src/main/java/expo/modules/felicareader/ExpoFelicaReaderModule.kt b/modules/expo-felica-reader/android/src/main/java/expo/modules/felicareader/ExpoFelicaReaderModule.kt
new file mode 100644
index 0000000..781ac3e
--- /dev/null
+++ b/modules/expo-felica-reader/android/src/main/java/expo/modules/felicareader/ExpoFelicaReaderModule.kt
@@ -0,0 +1,34 @@
+package expo.modules.felicareader
+
+import expo.modules.kotlin.modules.Module
+import expo.modules.kotlin.modules.ModuleDefinition
+import expo.modules.kotlin.Promise
+import android.nfc.NfcAdapter
+import android.nfc.Tag
+
+class NfcReaderCallback(private val promise: Promise) : NfcAdapter.ReaderCallback {
+ override fun onTagDiscovered(tag: Tag?) {
+ val idmString = tag?.id?.joinToString("") { "%02x".format(it) }
+ promise.resolve(idmString)
+ }
+}
+
+class ExpoFelicaReaderModule : Module() {
+ var nfcAdapter: NfcAdapter? = null
+ override fun definition() = ModuleDefinition {
+ Name("ExpoFelicaReader")
+
+ AsyncFunction("scan") { promise: Promise ->
+ nfcAdapter?.enableReaderMode(
+ appContext.currentActivity,
+ NfcReaderCallback(promise),
+ NfcAdapter.FLAG_READER_NFC_F,
+ null
+ )
+ }
+
+ OnCreate {
+ nfcAdapter = NfcAdapter.getDefaultAdapter(appContext.reactContext)
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/expo-felica-reader/expo-module.config.json b/modules/expo-felica-reader/expo-module.config.json
new file mode 100644
index 0000000..6952ae1
--- /dev/null
+++ b/modules/expo-felica-reader/expo-module.config.json
@@ -0,0 +1,9 @@
+{
+ "platforms": ["ios", "tvos", "android", "web"],
+ "ios": {
+ "modules": ["ExpoFelicaReaderModule"]
+ },
+ "android": {
+ "modules": ["expo.modules.felicareader.ExpoFelicaReaderModule"]
+ }
+}
diff --git a/modules/expo-felica-reader/ios/ExpoFelicaReader.podspec b/modules/expo-felica-reader/ios/ExpoFelicaReader.podspec
new file mode 100644
index 0000000..e19654c
--- /dev/null
+++ b/modules/expo-felica-reader/ios/ExpoFelicaReader.podspec
@@ -0,0 +1,27 @@
+require 'json'
+
+package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
+
+Pod::Spec.new do |s|
+ s.name = 'ExpoFelicaReader'
+ s.version = package['version']
+ s.summary = package['description']
+ s.description = package['description']
+ s.license = package['license']
+ s.author = package['author']
+ s.homepage = package['homepage']
+ s.platform = :ios, '13.0'
+ s.swift_version = '5.4'
+ s.source = { git: 'https://github.com/7nohe/expo-felica-reader' }
+ s.static_framework = true
+
+ s.dependency 'ExpoModulesCore'
+
+ # Swift/Objective-C compatibility
+ s.pod_target_xcconfig = {
+ 'DEFINES_MODULE' => 'YES',
+ 'SWIFT_COMPILATION_MODE' => 'wholemodule'
+ }
+
+ s.source_files = "**/*.{h,m,swift}"
+end
\ No newline at end of file
diff --git a/modules/expo-felica-reader/ios/ExpoFelicaReaderModule.swift b/modules/expo-felica-reader/ios/ExpoFelicaReaderModule.swift
new file mode 100644
index 0000000..6207600
--- /dev/null
+++ b/modules/expo-felica-reader/ios/ExpoFelicaReaderModule.swift
@@ -0,0 +1,70 @@
+import ExpoModulesCore
+import CoreNFC
+
+public class ExpoFelicaReaderModule: Module {
+ var session: NfcSession?
+ var semaphore: DispatchSemaphore?
+ public func definition() -> ModuleDefinition {
+ Name("ExpoFelicaReader")
+
+ AsyncFunction("scan") { (promise: Promise) in
+ session?.startSession()
+ DispatchQueue.global(qos: .background).async {
+ self.semaphore?.wait()
+ promise.resolve(self.session?.message)
+ }
+ }
+
+ OnCreate {
+ semaphore = DispatchSemaphore(value: 0)
+ session = NfcSession(semaphore: semaphore!)
+ }
+ }
+}
+
+class NfcSession: NSObject, NFCTagReaderSessionDelegate {
+ var session: NFCTagReaderSession?
+ let semaphore: DispatchSemaphore
+ var message: String?
+
+ init (semaphore: DispatchSemaphore) {
+ self.semaphore = semaphore
+ }
+
+ func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
+ print("tagReaderSessionDidBecomeActive")
+ }
+
+ func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
+ print("Error: \(error.localizedDescription)")
+ self.semaphore.signal()
+ self.session = nil
+ }
+
+ func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
+ let tag = tags.first!
+ session.connect(to: tag) { error in
+ if nil != error {
+ session.invalidate(errorMessage: "Error!")
+ self.semaphore.signal()
+ return
+ }
+ guard case .feliCa(let feliCaTag) = tag else {
+ session.invalidate(errorMessage: "This is not FeliCa!")
+ self.semaphore.signal()
+ return
+ }
+ let idm = feliCaTag.currentIDm.map { String(format: "%.2hhx", $0) }.joined()
+ self.message = idm
+ session.alertMessage = "Success!"
+ session.invalidate()
+ self.semaphore.signal()
+ }
+ }
+
+ func startSession() {
+ self.session = NFCTagReaderSession(pollingOption: [.iso14443, .iso15693, .iso18092], delegate: self, queue: nil)
+ session?.alertMessage = "Touch your FeliCa!"
+ session?.begin()
+ }
+}
\ No newline at end of file
diff --git a/modules/expo-felica-reader/src/ExpoFelicaReaderModule.ts b/modules/expo-felica-reader/src/ExpoFelicaReaderModule.ts
new file mode 100644
index 0000000..b74e342
--- /dev/null
+++ b/modules/expo-felica-reader/src/ExpoFelicaReaderModule.ts
@@ -0,0 +1,5 @@
+import { requireNativeModule } from 'expo-modules-core';
+
+// It loads the native module object from the JSI or falls back to
+// the bridge module (from NativeModulesProxy) if the remote debugger is on.
+export default requireNativeModule('ExpoFelicaReader');
diff --git a/modules/expo-felica-reader/src/index.ts b/modules/expo-felica-reader/src/index.ts
new file mode 100644
index 0000000..0b3a437
--- /dev/null
+++ b/modules/expo-felica-reader/src/index.ts
@@ -0,0 +1,5 @@
+import ExpoFelicaReaderModule from "./ExpoFelicaReaderModule";
+
+export async function scan(): Promise {
+ return await ExpoFelicaReaderModule.scan();
+}
diff --git a/package.json b/package.json
index b337ffa..862f402 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,6 @@
"expo": "^50.0.11",
"expo-dev-client": "~3.3.9",
"expo-device": "~5.9.3",
- "expo-felica-reader": "^0.1.0",
"expo-font": "~11.10.3",
"expo-location": "~16.5.5",
"expo-notifications": "~0.27.6",
diff --git a/yarn.lock b/yarn.lock
index 55b07dc..8445880 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5246,11 +5246,6 @@ expo-eas-client@~0.11.0:
resolved "https://registry.yarnpkg.com/expo-eas-client/-/expo-eas-client-0.11.2.tgz#2e8d6f347dcea38b58c2b6a21db7c632383fb1ba"
integrity sha512-SY7rVFxb4ut/OMTgR7A39Jg+8+hXwQNRpZd+RBpB+B5XV2STj/pWXHnGFhBayEF4umI4SxrOvisY90rlPWVO9Q==
-expo-felica-reader@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/expo-felica-reader/-/expo-felica-reader-0.1.0.tgz#968a9bb93d1f040f8e8dfbc899fba0214327c8b0"
- integrity sha512-uDv5/eeaCpMOJ3R3supaE2m7VJZGaDE6C3AdWf3Y1pgVzteI3GUah5+doFpadf6CSjytznix5U1pTLbeSHeuUw==
-
expo-file-system@~16.0.0, expo-file-system@~16.0.8:
version "16.0.8"
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-16.0.8.tgz#13c79a8e06e42a8e76e9297df6920597a011d989"