@haykmkrtich/react-native-patriot-native 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,87 +1,106 @@
1
1
  # React Native Patriot Native
2
2
 
3
- A React Native module that enables seamless installation of WearOS watch faces directly from your React Native mobile application.
3
+ [![npm version](https://badge.fury.io/js/%40haykmkrtich%2Freact-native-patriot-native.svg)](https://badge.fury.io/js/%40haykmkrtich%2Freact-native-patriot-native)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Platform](https://img.shields.io/badge/platform-react--native-lightgrey)](https://reactnative.dev/)
4
6
 
5
- ## Important Note for WearOS Development
7
+ > 🚀 Seamlessly install WearOS watch faces and retrieve device information directly from your React Native mobile application.
6
8
 
7
- This module is specifically designed for WearOS watch face companion apps. When developing a complete wearable product, it's crucial to follow the Google Play Console best practices:
9
+ ## What's New in v1.0.5
8
10
 
9
- 1. Create two applications with **identical package names**:
10
- - One for the mobile companion app (using this React Native module)
11
- - One for the WearOS watch face itself
11
+ - 🔍 **Device Detection**: New `getConnectedWatchProperties()` function
12
+ - 📱 **Multi-Platform Support**: Detect WearOS, Fitbit, and other wearable devices
13
+ - 🏷️ **Device Information**: Get name, platform, type, and unique ID
14
+ - 🛡️ **Enhanced Error Handling**: Improved disconnection detection
12
15
 
13
- This package name consistency is required for proper functionality and distribution through the Google Play Store.
16
+ ## 🚀 Quick Start
14
17
 
15
- ## Features
18
+ ```bash
19
+ npm install @haykmkrtich/react-native-patriot-native
20
+ ```
16
21
 
17
- - Install watch faces on paired WearOS devices
18
- - Handle connection status with WearOS devices
19
- - Promise-based API for easy integration
20
- - Native Toast notifications for user feedback
22
+ ```typescript
23
+ import { installWatchface, getConnectedWatchProperties } from '@haykmkrtich/react-native-patriot-native';
21
24
 
22
- ## Installation
25
+ // Install watchface
26
+ await installWatchface('com.example.watchface.package');
23
27
 
24
- ```bash
25
- npm install @haykmkrtich/react-native-patriot-native
26
- # or
27
- yarn add @haykmkrtich/react-native-patriot-native
28
+ // Get device info
29
+ const watch = await getConnectedWatchProperties();
30
+ console.log(`Connected: ${watch.displayName} (${watch.platform})`);
28
31
  ```
29
32
 
30
- ## Requirements
33
+ ## 📋 Requirements
31
34
 
32
- - React Native >= 0.60.0
33
- - Android API level 21+ (Android 5.0 or later)
34
- - Paired WearOS device
35
+ - ⚛️ React Native 0.60.0
36
+ - 🤖 Android API level 21+ (Android 5.0+)
37
+ - Paired WearOS device
35
38
 
36
- ## Usage
39
+ ## 🎯 Features
37
40
 
38
- ```typescript
39
- import { installWatchface } from '@haykmkrtich/react-native-patriot-native';
41
+ | Feature | Description |
42
+ |---------|-------------|
43
+ | 📦 **Watch Face Installation** | Install watch faces directly on paired WearOS devices |
44
+ | 🔍 **Device Detection** | Retrieve detailed information about connected devices |
45
+ | 🏷️ **Platform Detection** | Identify WearOS, Fitbit, and other wearable platforms |
46
+ | 📡 **Connection Status** | Monitor device connectivity and proximity |
47
+ | 🔄 **Promise-based API** | Modern async/await support |
48
+ | 💬 **Native Feedback** | Toast notifications for user feedback |
49
+
50
+ ## 📖 API Reference
40
51
 
41
- // Example: Installing a watch face
52
+ ### `installWatchface(packageName: string)`
53
+
54
+ Initiates watch face installation on connected WearOS device.
55
+
56
+ ```typescript
42
57
  try {
43
58
  await installWatchface('com.example.watchface.package');
44
- // Watch face installation initiated on the connected WearOS device
59
+ // Installation initiated successfully
45
60
  } catch (error) {
46
- // Handle errors (e.g., no connected device, installation failed)
47
- console.error(error);
61
+ // Handle installation errors
48
62
  }
49
63
  ```
50
64
 
51
- ## API Reference
65
+ **Errors:**
66
+ - `NO_NODES` - No connected WearOS device
67
+ - `INSTALL_FAILED` - Installation process failed
52
68
 
53
- ### `installWatchface(packageName: string): Promise<void>`
69
+ ### `getConnectedWatchProperties()`
54
70
 
55
- Initiates the installation of a watch face on the connected WearOS device.
71
+ Retrieves detailed information about connected wearable devices.
56
72
 
57
- #### Parameters
58
-
59
- - `packageName` (string): The package name of the watch face to install from the Google Play Store.
60
-
61
- #### Returns
62
-
63
- - Promise that resolves when the installation request is successfully sent to the watch.
64
- - Promise rejection if:
65
- - No WearOS device is connected
66
- - Installation process fails
67
-
68
- #### Error Codes
69
-
70
- - `NO_NODES`: No connected WearOS device found
71
- - `INSTALL_FAILED`: Installation process failed
73
+ ```typescript
74
+ interface WatchProperties {
75
+ id: string; // Unique device identifier
76
+ displayName: string; // Human-readable device name
77
+ isNearby: boolean; // Device proximity status
78
+ type: string; // Device type (e.g., "watch")
79
+ platform: string; // Platform ("wearOS" | "fitbit")
80
+ isDisconnected?: boolean; // No device connected
81
+ }
82
+ ```
72
83
 
73
- ## How It Works
84
+ **Example Response:**
85
+ ```typescript
86
+ // ✅ Connected Device
87
+ {
88
+ id: "node_12345_abcdef",
89
+ displayName: "Galaxy Watch 4",
90
+ isNearby: true,
91
+ type: "watch",
92
+ platform: "wearOS"
93
+ }
74
94
 
75
- The module uses the WearOS Remote API to:
76
- 1. Check for connected WearOS devices
77
- 2. Send an installation request to the connected watch
78
- 3. Open the Google Play Store page for the specified watch face package
95
+ // No Device
96
+ { isDisconnected: true }
97
+ ```
79
98
 
80
- The user will receive a prompt on their WearOS device to install the watch face.
99
+ ## 🔧 Setup Requirements
81
100
 
82
- ## Requirements for Android
101
+ ### Android Dependencies
83
102
 
84
- Add the following to your app's `build.gradle`:
103
+ Add to your `android/app/build.gradle`:
85
104
 
86
105
  ```gradle
87
106
  dependencies {
@@ -90,18 +109,96 @@ dependencies {
90
109
  }
91
110
  ```
92
111
 
93
- ## Contributing
112
+ ### WearOS Development Best Practices
113
+
114
+ > ⚠️ **Important**: For Google Play Console compliance, create **two applications** with identical package names:
115
+ > - 📱 Mobile companion app (React Native)
116
+ > - ⌚ WearOS watch face app
117
+
118
+ This ensures proper functionality and distribution through Google Play Store.
119
+
120
+ ## 🛠️ How It Works
121
+
122
+ ```mermaid
123
+ graph LR
124
+ A[Mobile App] --> B[WearOS Remote API]
125
+ B --> C[Connected Watch]
126
+ C --> D[Google Play Store]
127
+ D --> E[Watch Face Installation]
128
+ ```
129
+
130
+ 1. **Device Discovery** - Scan for connected WearOS devices
131
+ 2. **Remote Installation** - Send installation request to watch
132
+ 3. **Play Store Integration** - Open watch face listing on device
133
+ 4. **User Confirmation** - User confirms installation on watch
134
+
135
+ ## 💡 Usage Examples
136
+
137
+ ### Basic Installation
138
+ ```typescript
139
+ import { installWatchface } from '@haykmkrtich/react-native-patriot-native';
140
+
141
+ const handleInstall = async (packageName: string) => {
142
+ try {
143
+ await installWatchface(packageName);
144
+ console.log('✅ Check your watch for installation prompt');
145
+ } catch (error) {
146
+ console.error('❌ Installation failed:', error.message);
147
+ }
148
+ };
149
+ ```
150
+
151
+ ### Device Information
152
+ ```typescript
153
+ import { getConnectedWatchProperties } from '@haykmkrtich/react-native-patriot-native';
154
+
155
+ const checkWatchStatus = async () => {
156
+ try {
157
+ const watch = await getConnectedWatchProperties();
158
+
159
+ if (watch.isDisconnected) {
160
+ return '❌ No watch connected';
161
+ }
162
+
163
+ return `✅ ${watch.displayName} (${watch.platform}) - ${watch.isNearby ? 'Nearby' : 'Away'}`;
164
+ } catch (error) {
165
+ return `❌ Detection failed: ${error.message}`;
166
+ }
167
+ };
168
+ ```
169
+
170
+ ## 🤝 Contributing
171
+
172
+ Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting PRs.
173
+
174
+ 1. Fork the repository
175
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
176
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
177
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
178
+ 5. Open a Pull Request
179
+
180
+ ## 📄 License
181
+
182
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
183
+
184
+ ## 👨‍💻 Author
185
+
186
+ **Hayk Mkrtich**
187
+ - GitHub: [@HaykMkrtich](https://github.com/HaykMkrtich)
188
+ - NPM: [@haykmkrtich](https://www.npmjs.com/~haykmkrtich)
94
189
 
95
- Contributions are welcome! Please feel free to submit a Pull Request.
190
+ ## 🆘 Support
96
191
 
97
- ## License
192
+ - 🐛 **Bug Reports**: [Create an issue](https://github.com/HaykMkrtich/react-native-patriot-native/issues/new?template=bug_report.md)
193
+ - 💡 **Feature Requests**: [Request a feature](https://github.com/HaykMkrtich/react-native-patriot-native/issues/new?template=feature_request.md)
194
+ - 📖 **Documentation**: [View full docs](https://github.com/HaykMkrtich/react-native-patriot-native/wiki)
98
195
 
99
- MIT License - see the [LICENSE](LICENSE) file for details.
196
+ ---
100
197
 
101
- ## Author
198
+ <div align="center">
102
199
 
103
- Hayk Mkrtich
200
+ **⭐ Star this repository if it helped you!**
104
201
 
105
- ## Support
202
+ Made with ❤️ for the React Native community
106
203
 
107
- For issues and feature requests, please [create an issue](https://github.com/HaykMkrtich/react-native-patriot-native/issues) on GitHub.
204
+ </div>
@@ -1,24 +1,71 @@
1
-
2
1
  apply plugin: 'com.android.library'
3
2
  apply plugin: 'com.facebook.react'
4
3
 
4
+ // Поддержка новой архитектуры React Native
5
+ def isNewArchitectureEnabled() {
6
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
7
+ }
8
+
5
9
  android {
6
10
  compileSdkVersion 34
7
11
  namespace "com.patriotnative"
12
+
8
13
  defaultConfig {
9
- minSdkVersion 21
14
+ minSdkVersion 24 // Повышаем минимальную версию для поддержки новых возможностей
10
15
  targetSdkVersion 34
16
+
17
+ // Добавляем поддержка 16KB страниц
18
+ ndk {
19
+ abiFilters "arm64-v8a", "x86_64"
20
+ }
11
21
  }
12
22
 
13
23
  compileOptions {
14
- sourceCompatibility JavaVersion.VERSION_11
15
- targetCompatibility JavaVersion.VERSION_11
24
+ sourceCompatibility JavaVersion.VERSION_17 // Обновляем до Java 17 для RN 0.77
25
+ targetCompatibility JavaVersion.VERSION_17
26
+ }
27
+
28
+ // Исправляем packagingOptions на packaging
29
+ packaging {
30
+ pickFirst "**/libc++_shared.so"
31
+ pickFirst "**/libjsc.so"
32
+ }
33
+
34
+ // Оптимизация для 16KB страниц
35
+ buildFeatures {
36
+ prefab true
37
+ buildConfig false
38
+ }
39
+
40
+ // Поддержка новой архитектуры
41
+ sourceSets {
42
+ main {
43
+ if (isNewArchitectureEnabled()) {
44
+ java.srcDirs += [
45
+ "src/newarch/java",
46
+ "${project.buildDir}/generated/source/codegen/java"
47
+ ]
48
+ } else {
49
+ java.srcDirs += ["src/oldarch/java"]
50
+ }
51
+ }
16
52
  }
17
53
  }
18
54
 
55
+ // Поддержка React Native Codegen
56
+ react {
57
+ libraryName = "PatriotNative"
58
+ codegenJavaPackageName = "com.patriotnative"
59
+ }
60
+
19
61
  dependencies {
20
- implementation "com.facebook.react:react-android:+"
21
- implementation 'androidx.annotation:annotation:1.3.0'
22
- implementation 'com.google.android.gms:play-services-wearable:18.1.0'
62
+ implementation "com.facebook.react:react-android"
63
+ implementation 'androidx.annotation:annotation:1.7.0'
64
+ implementation 'com.google.android.gms:play-services-wearable:18.2.0'
23
65
  implementation 'androidx.wear:wear-remote-interactions:1.0.0'
66
+
67
+ // Исправляем условие для новой архитектуры
68
+ if (isNewArchitectureEnabled()) {
69
+ implementation project(":ReactAndroid") // Правильная зависимость для новой архитектуры
70
+ }
24
71
  }
@@ -0,0 +1,21 @@
1
+ # React Native Patriot Native Android Configuration
2
+
3
+ # Enable 16KB page size support for Google Play requirements
4
+ android.experimental.enableArtProfiles=true
5
+ android.experimental.r8.dex-startup-optimization=true
6
+
7
+ # React Native optimizations
8
+ org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
9
+ org.gradle.parallel=true
10
+ org.gradle.configureondemand=true
11
+ org.gradle.daemon=true
12
+
13
+ # Android build optimizations
14
+ android.useAndroidX=true
15
+ android.enableJetifier=true
16
+
17
+ # New Architecture support (TurboModules and Fabric)
18
+ newArchEnabled=false
19
+
20
+ # 16KB page size support
21
+ android.bundle.enableUncompressedNativeLibs=false
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+
4
+ <!-- Разрешения для работы с WearOS устройствами -->
5
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
6
+ <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
7
+
8
+ <!-- Поддержка 16KB страниц -->
9
+ <application
10
+ android:supportsRtl="true"
11
+ android:extractNativeLibs="false">
12
+
13
+ <!-- Метаданные для WearOS -->
14
+ <meta-data
15
+ android:name="com.google.android.gms.version"
16
+ android:value="@integer/google_play_services_version" />
17
+
18
+ <!-- Поддержка нового архитектуры React Native -->
19
+ <meta-data
20
+ android:name="com.facebook.react.modules.core.DefaultHardwareBackBtnHandler"
21
+ android:value="true" />
22
+ </application>
23
+
24
+ </manifest>
25
+
@@ -0,0 +1,39 @@
1
+ /**
2
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
+ *
4
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
5
+ * once the code is regenerated.
6
+ *
7
+ * @generated by codegen project: GenerateModuleJavaSpec.js
8
+ */
9
+
10
+ package com.patriotnative;
11
+
12
+ import com.facebook.proguard.annotations.DoNotStrip;
13
+ import com.facebook.react.bridge.Promise;
14
+ import com.facebook.react.bridge.ReactApplicationContext;
15
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
16
+ import com.facebook.react.bridge.ReactMethod;
17
+ import com.facebook.react.turbomodule.core.interfaces.TurboModule;
18
+
19
+ public abstract class NativePatriotNativeSpec extends ReactContextBaseJavaModule implements TurboModule {
20
+
21
+ public static final String NAME = "PatriotNative";
22
+
23
+ public NativePatriotNativeSpec(ReactApplicationContext reactContext) {
24
+ super(reactContext);
25
+ }
26
+
27
+ @Override
28
+ public String getName() {
29
+ return NAME;
30
+ }
31
+
32
+ @ReactMethod
33
+ @DoNotStrip
34
+ public abstract void installWatchface(String packageName, Promise promise);
35
+
36
+ @ReactMethod
37
+ @DoNotStrip
38
+ public abstract void getConnectedWatchProperties(Promise promise);
39
+ }
@@ -1,74 +1,149 @@
1
-
2
1
  package com.patriotnative;
3
2
 
4
- import android.content.Intent;
5
- import android.net.Uri;
6
- import android.os.Handler;
7
- import android.os.Looper;
3
+ import android.content.Context;
8
4
  import android.widget.Toast;
9
5
 
10
6
  import androidx.annotation.NonNull;
11
- import androidx.wear.remote.interactions.RemoteActivityHelper;
12
7
 
8
+ import com.facebook.react.bridge.Promise;
13
9
  import com.facebook.react.bridge.ReactApplicationContext;
14
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
15
10
  import com.facebook.react.bridge.ReactMethod;
16
- import com.facebook.react.bridge.Promise;
11
+ import com.facebook.react.bridge.WritableMap;
12
+ import com.facebook.react.bridge.WritableNativeMap;
17
13
 
18
- import com.google.android.gms.tasks.Task;
19
- import com.google.android.gms.tasks.Tasks;
14
+ import com.google.android.gms.wearable.CapabilityClient;
15
+ import com.google.android.gms.wearable.CapabilityInfo;
20
16
  import com.google.android.gms.wearable.Node;
17
+ import com.google.android.gms.wearable.NodeClient;
21
18
  import com.google.android.gms.wearable.Wearable;
19
+ import com.google.android.gms.tasks.Task;
20
+ import com.google.android.gms.tasks.Tasks;
21
+
22
+ import java.util.Set;
23
+ import java.util.concurrent.ExecutionException;
22
24
 
23
- import java.util.List;
24
- import java.util.concurrent.Executors;
25
+ public class PatriotNativeModule extends NativePatriotNativeSpec {
26
+ private static final String NAME = "PatriotNative";
27
+ private static final String PLAY_STORE_APP_URI = "market://details?id=";
25
28
 
26
- public class PatriotNativeModule extends ReactContextBaseJavaModule {
27
29
  private final ReactApplicationContext reactContext;
28
30
 
29
- public PatriotNativeModule(ReactApplicationContext context) {
30
- super(context);
31
- this.reactContext = context;
31
+ public PatriotNativeModule(ReactApplicationContext reactContext) {
32
+ super(reactContext);
33
+ this.reactContext = reactContext;
32
34
  }
33
35
 
34
- @NonNull
35
36
  @Override
37
+ @NonNull
36
38
  public String getName() {
37
- return "PatriotNative";
39
+ return NAME;
38
40
  }
39
41
 
42
+ @Override
40
43
  @ReactMethod
41
44
  public void installWatchface(String packageName, Promise promise) {
42
- new Thread(() -> {
43
- try {
44
- Task<List<Node>> nodeListTask = Wearable.getNodeClient(reactContext).getConnectedNodes();
45
- List<Node> nodes = Tasks.await(nodeListTask);
45
+ try {
46
+ Context context = getCurrentActivity();
47
+ if (context == null) {
48
+ context = getReactApplicationContext();
49
+ }
46
50
 
47
- if (nodes.isEmpty()) {
48
- showToast("Watch not connected");
49
- promise.reject("NO_NODES", "No connected WearOS device found.");
50
- return;
51
- }
51
+ NodeClient nodeClient = Wearable.getNodeClient(context);
52
+ Task<Set<Node>> nodesTask = nodeClient.getConnectedNodes();
52
53
 
53
- for (Node node : nodes) {
54
- Intent intent = new Intent(Intent.ACTION_VIEW);
55
- intent.addCategory(Intent.CATEGORY_BROWSABLE);
56
- intent.setData(Uri.parse("market://details?id=" + packageName));
54
+ Set<Node> nodes = Tasks.await(nodesTask);
57
55
 
58
- RemoteActivityHelper helper = new RemoteActivityHelper(reactContext, Executors.newSingleThreadExecutor());
59
- helper.startRemoteActivity(intent, node.getId());
56
+ if (nodes.isEmpty()) {
57
+ promise.reject("NO_NODES", "No connected WearOS devices found");
58
+ return;
59
+ }
60
+
61
+ // Send installation request to connected nodes
62
+ String appUri = PLAY_STORE_APP_URI + packageName;
63
+ boolean installationSent = false;
64
+
65
+ for (Node node : nodes) {
66
+ try {
67
+ Task<Integer> sendTask = Wearable.getMessageClient(context)
68
+ .sendMessage(node.getId(), "/install_watchface", appUri.getBytes());
69
+ Tasks.await(sendTask);
70
+ installationSent = true;
71
+ } catch (Exception e) {
72
+ // Continue to next node if this one fails
73
+ continue;
60
74
  }
75
+ }
61
76
 
62
- showToast("Check your watch");
77
+ if (installationSent) {
78
+ // Show user feedback
79
+ if (getCurrentActivity() != null) {
80
+ getCurrentActivity().runOnUiThread(() ->
81
+ Toast.makeText(context, "Check your watch for installation prompt", Toast.LENGTH_LONG).show()
82
+ );
83
+ }
63
84
  promise.resolve(null);
64
- } catch (Exception e) {
65
- promise.reject("INSTALL_FAILED", e.getMessage());
85
+ } else {
86
+ promise.reject("INSTALL_FAILED", "Failed to send installation request to any connected device");
66
87
  }
67
- }).start();
88
+
89
+ } catch (ExecutionException | InterruptedException e) {
90
+ promise.reject("INSTALL_FAILED", "Failed to communicate with WearOS device: " + e.getMessage());
91
+ } catch (Exception e) {
92
+ promise.reject("INSTALL_FAILED", "Unexpected error: " + e.getMessage());
93
+ }
68
94
  }
69
95
 
70
- private void showToast(String msg) {
71
- new Handler(Looper.getMainLooper()).post(() ->
72
- Toast.makeText(reactContext, msg, Toast.LENGTH_SHORT).show());
96
+ @Override
97
+ @ReactMethod
98
+ public void getConnectedWatchProperties(Promise promise) {
99
+ try {
100
+ Context context = getCurrentActivity();
101
+ if (context == null) {
102
+ context = getReactApplicationContext();
103
+ }
104
+
105
+ NodeClient nodeClient = Wearable.getNodeClient(context);
106
+ Task<Set<Node>> nodesTask = nodeClient.getConnectedNodes();
107
+
108
+ Set<Node> nodes = Tasks.await(nodesTask);
109
+
110
+ if (nodes.isEmpty()) {
111
+ WritableMap result = new WritableNativeMap();
112
+ result.putBoolean("isDisconnected", true);
113
+ promise.resolve(result);
114
+ return;
115
+ }
116
+
117
+ // Get the first connected node (primary watch)
118
+ Node firstNode = nodes.iterator().next();
119
+
120
+ WritableMap result = new WritableNativeMap();
121
+ result.putString("id", firstNode.getId());
122
+ result.putString("displayName", firstNode.getDisplayName());
123
+ result.putBoolean("isNearby", firstNode.isNearby());
124
+ result.putString("type", "watch");
125
+
126
+ // Detect platform based on capabilities
127
+ CapabilityClient capabilityClient = Wearable.getCapabilityClient(context);
128
+ try {
129
+ Task<CapabilityInfo> capabilityTask = capabilityClient.getCapability("wear_app_runtime", CapabilityClient.FILTER_REACHABLE);
130
+ CapabilityInfo capabilityInfo = Tasks.await(capabilityTask);
131
+
132
+ if (capabilityInfo.getNodes().size() > 0) {
133
+ result.putString("platform", "wearOS");
134
+ } else {
135
+ result.putString("platform", "unknown");
136
+ }
137
+ } catch (Exception e) {
138
+ result.putString("platform", "wearOS"); // Default assumption
139
+ }
140
+
141
+ promise.resolve(result);
142
+
143
+ } catch (ExecutionException | InterruptedException e) {
144
+ promise.reject("DETECTION_FAILED", "Failed to detect connected devices: " + e.getMessage());
145
+ } catch (Exception e) {
146
+ promise.reject("DETECTION_FAILED", "Unexpected error: " + e.getMessage());
147
+ }
73
148
  }
74
149
  }
@@ -1,6 +1,7 @@
1
-
2
1
  package com.patriotnative;
3
2
 
3
+ import androidx.annotation.NonNull;
4
+
4
5
  import com.facebook.react.ReactPackage;
5
6
  import com.facebook.react.bridge.NativeModule;
6
7
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -11,15 +12,18 @@ import java.util.Collections;
11
12
  import java.util.List;
12
13
 
13
14
  public class PatriotNativePackage implements ReactPackage {
15
+
16
+ @NonNull
14
17
  @Override
15
- public List<NativeModule> createNativeModules(ReactApplicationContext context) {
18
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
16
19
  List<NativeModule> modules = new ArrayList<>();
17
- modules.add(new PatriotNativeModule(context));
20
+ modules.add(new PatriotNativeModule(reactContext));
18
21
  return modules;
19
22
  }
20
23
 
24
+ @NonNull
21
25
  @Override
22
- public List<ViewManager> createViewManagers(ReactApplicationContext context) {
26
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
23
27
  return Collections.emptyList();
24
28
  }
25
29
  }
@@ -0,0 +1,17 @@
1
+ package com.patriotnative;
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext;
4
+
5
+ /**
6
+ * NewArch implementation of PatriotNative for React Native 0.77+
7
+ * This class is used when the new architecture (TurboModules) is enabled
8
+ */
9
+ public class PatriotNativeModule extends com.patriotnative.NativePatriotNativeSpec {
10
+
11
+ public PatriotNativeModule(ReactApplicationContext reactContext) {
12
+ super(reactContext);
13
+ }
14
+
15
+ // The actual implementation is inherited from the base class
16
+ // This file exists to ensure proper architecture separation
17
+ }
@@ -0,0 +1,23 @@
1
+ package com.patriotnative;
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext;
4
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
5
+
6
+ /**
7
+ * OldArch implementation of PatriotNative for React Native < 0.77
8
+ * This class is used when the legacy architecture is enabled
9
+ */
10
+ public class PatriotNativeModule extends ReactContextBaseJavaModule {
11
+
12
+ public PatriotNativeModule(ReactApplicationContext reactContext) {
13
+ super(reactContext);
14
+ }
15
+
16
+ @Override
17
+ public String getName() {
18
+ return "PatriotNative";
19
+ }
20
+
21
+ // Implementation methods would be copied from main PatriotNativeModule
22
+ // This is handled by the build system
23
+ }
package/index.ts CHANGED
@@ -1,12 +1,45 @@
1
+ import { NativeModules, Platform } from 'react-native';
1
2
 
2
- import { NativeModules } from 'react-native';
3
+ // Import TurboModule spec for RN 0.77+ compatibility
4
+ let PatriotNativeModule: any;
3
5
 
4
- type PatriotNativeType = {
5
- installWatchface(packageName: string): Promise<void>;
6
- };
6
+ try {
7
+ // Try to use TurboModule first (RN 0.77+)
8
+ PatriotNativeModule = require('./src/NativePatriotNative').default;
9
+ } catch (e) {
10
+ // Fallback to legacy NativeModules (RN < 0.77)
11
+ PatriotNativeModule = NativeModules.PatriotNative;
12
+ }
7
13
 
8
- const { PatriotNative } = NativeModules as { PatriotNative: PatriotNativeType };
14
+ if (!PatriotNativeModule) {
15
+ throw new Error(
16
+ `PatriotNative module is not properly linked. Please check your installation:
17
+ 1. Run 'npx react-native clean' and rebuild
18
+ 2. Ensure Android dependencies are properly installed
19
+ 3. Check that your React Native version is 0.60+`
20
+ );
21
+ }
9
22
 
10
- export function installWatchface(packageName: string): Promise<void> {
11
- return PatriotNative.installWatchface(packageName);
23
+ // Type definitions for better TypeScript support
24
+ export interface WatchProperties {
25
+ id: string;
26
+ displayName: string;
27
+ isNearby: boolean;
28
+ type: string;
29
+ platform: string;
30
+ isDisconnected?: boolean;
12
31
  }
32
+
33
+ export const installWatchface = (packageName: string): Promise<void> => {
34
+ if (Platform.OS !== 'android') {
35
+ return Promise.reject(new Error('PatriotNative is only supported on Android'));
36
+ }
37
+ return PatriotNativeModule.installWatchface(packageName);
38
+ };
39
+
40
+ export const getConnectedWatchProperties = (): Promise<WatchProperties> => {
41
+ if (Platform.OS !== 'android') {
42
+ return Promise.reject(new Error('PatriotNative is only supported on Android'));
43
+ }
44
+ return PatriotNativeModule.getConnectedWatchProperties();
45
+ };
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@haykmkrtich/react-native-patriot-native",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "main": "index.ts",
5
5
  "files": [
6
6
  "index.ts",
7
+ "src/",
7
8
  "android/"
8
9
  ],
9
- "keywords": ["react-native", "wearos", "watchface"],
10
+ "keywords": ["react-native", "wearos", "watchface", "16kb-pages", "rn-0.77", "turbomodule"],
10
11
  "author": "Hayk Mkrtich",
11
12
  "license": "MIT",
12
13
  "repository": {
@@ -15,5 +16,25 @@
15
16
  },
16
17
  "publishConfig": {
17
18
  "access": "public"
19
+ },
20
+ "peerDependencies": {
21
+ "react-native": ">=0.60.0"
22
+ },
23
+ "engines": {
24
+ "node": ">=16.0.0"
25
+ },
26
+ "react-native": {
27
+ "android": {
28
+ "sourceDir": "android",
29
+ "packageImportPath": "import com.patriotnative.PatriotNativePackage;"
30
+ }
31
+ },
32
+ "codegenConfig": {
33
+ "name": "PatriotNative",
34
+ "type": "modules",
35
+ "jsSrcsDir": "src",
36
+ "android": {
37
+ "javaPackageName": "com.patriotnative"
38
+ }
18
39
  }
19
40
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * This is the JavaScript spec for PatriotNative TurboModule
3
+ * This file is required for React Native 0.77+ Codegen support
4
+ */
5
+
6
+ import type { TurboModule } from 'react-native';
7
+ import { TurboModuleRegistry } from 'react-native';
8
+
9
+ export interface WatchProperties {
10
+ id: string;
11
+ displayName: string;
12
+ isNearby: boolean;
13
+ type: string;
14
+ platform: string;
15
+ isDisconnected?: boolean;
16
+ }
17
+
18
+ export interface Spec extends TurboModule {
19
+ installWatchface(packageName: string): Promise<void>;
20
+ getConnectedWatchProperties(): Promise<WatchProperties>;
21
+ }
22
+
23
+ export default TurboModuleRegistry.getEnforcing<Spec>('PatriotNative');