feat(pos): Capacitor mobile app setup — Android + iOS wrapper
Set up Capacitor to wrap the Nexus POS web app as a native mobile app. The app loads from the remote server URL so no bundling is needed. Includes native-bridge.js for camera, push notifications, haptics, and status bar integration when running inside the native shell. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
4
pos/.gitignore
vendored
Normal file
4
pos/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
android/
|
||||
ios/
|
||||
.gradle/
|
||||
17
pos/capacitor.config.json
Normal file
17
pos/capacitor.config.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"appId": "com.nexusautoparts.pos",
|
||||
"appName": "Nexus POS",
|
||||
"webDir": "www",
|
||||
"server": {
|
||||
"url": "https://nexus.consultoria-as.com/pos",
|
||||
"cleartext": true
|
||||
},
|
||||
"plugins": {
|
||||
"SplashScreen": {
|
||||
"launchShowDuration": 2000,
|
||||
"backgroundColor": "#0d0d0d",
|
||||
"showSpinner": true,
|
||||
"spinnerColor": "#F5A623"
|
||||
}
|
||||
}
|
||||
}
|
||||
50
pos/mobile/README.md
Normal file
50
pos/mobile/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Nexus POS — Mobile App Build Guide
|
||||
|
||||
## Prerequisites
|
||||
- Node.js 18+
|
||||
- Android Studio (for Android)
|
||||
- Xcode 15+ (for iOS, macOS only)
|
||||
|
||||
## Architecture
|
||||
|
||||
The Capacitor app loads the POS from the remote server at
|
||||
`https://nexus.consultoria-as.com/pos`. This means:
|
||||
- The app requires internet on first load.
|
||||
- The PWA service worker handles offline caching after that.
|
||||
- No HTML/JS/CSS is bundled into the native binary.
|
||||
|
||||
## Android Build
|
||||
|
||||
```bash
|
||||
cd /home/Autopartes/pos
|
||||
npx cap sync android
|
||||
npx cap open android
|
||||
# In Android Studio: Build > Generate Signed APK
|
||||
```
|
||||
|
||||
## iOS Build
|
||||
|
||||
```bash
|
||||
cd /home/Autopartes/pos
|
||||
npx cap sync ios
|
||||
npx cap open ios
|
||||
# In Xcode: Product > Archive
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
npx cap run android --livereload --external
|
||||
npx cap run ios --livereload --external
|
||||
```
|
||||
|
||||
## App Icons & Splash Screens
|
||||
|
||||
Place source images in `mobile/resources/`:
|
||||
- `icon.png` — 1024x1024 app icon
|
||||
- `splash.png` — 2732x2732 splash screen
|
||||
|
||||
Then generate platform assets:
|
||||
```bash
|
||||
npx @capacitor/assets generate
|
||||
```
|
||||
BIN
pos/mobile/resources/icon.png
Normal file
BIN
pos/mobile/resources/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
1135
pos/package-lock.json
generated
Normal file
1135
pos/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
pos/package.json
Normal file
24
pos/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "pos",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"@capacitor/android": "^8.3.0",
|
||||
"@capacitor/camera": "^8.0.2",
|
||||
"@capacitor/cli": "^7.6.1",
|
||||
"@capacitor/core": "^8.3.0",
|
||||
"@capacitor/haptics": "^8.0.2",
|
||||
"@capacitor/ios": "^8.3.0",
|
||||
"@capacitor/push-notifications": "^8.0.3",
|
||||
"@capacitor/splash-screen": "^8.0.1",
|
||||
"@capacitor/status-bar": "^8.0.2"
|
||||
}
|
||||
}
|
||||
72
pos/static/js/native-bridge.js
Normal file
72
pos/static/js/native-bridge.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// native-bridge.js — Detects if running inside Capacitor native app
|
||||
// and provides native API access (camera for barcode, push notifications, haptics)
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.NexusNative = {
|
||||
isNative: typeof Capacitor !== 'undefined',
|
||||
|
||||
// Camera for barcode scanning
|
||||
async scanBarcode() {
|
||||
if (!this.isNative) return null;
|
||||
try {
|
||||
const { Camera } = await import('@capacitor/camera');
|
||||
const photo = await Camera.getPhoto({
|
||||
quality: 90,
|
||||
resultType: 'base64'
|
||||
});
|
||||
// In production, send to a barcode decode service
|
||||
return photo;
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// Push notification registration
|
||||
async registerPush() {
|
||||
if (!this.isNative) return null;
|
||||
try {
|
||||
const { PushNotifications } = await import('@capacitor/push-notifications');
|
||||
const result = await PushNotifications.requestPermissions();
|
||||
if (result.receive === 'granted') {
|
||||
await PushNotifications.register();
|
||||
}
|
||||
PushNotifications.addListener('registration', token => {
|
||||
console.log('Push token:', token.value);
|
||||
// Send token to server for this employee
|
||||
});
|
||||
PushNotifications.addListener('pushNotificationReceived', notification => {
|
||||
console.log('Push received:', notification);
|
||||
});
|
||||
} catch(e) {
|
||||
console.log('Push not available:', e);
|
||||
}
|
||||
},
|
||||
|
||||
// Haptic feedback
|
||||
async vibrate() {
|
||||
if (!this.isNative) return;
|
||||
try {
|
||||
const { Haptics, ImpactStyle } = await import('@capacitor/haptics');
|
||||
await Haptics.impact({ style: ImpactStyle.Light });
|
||||
} catch(e) {}
|
||||
},
|
||||
|
||||
// Status bar (hide for fullscreen POS)
|
||||
async setupStatusBar() {
|
||||
if (!this.isNative) return;
|
||||
try {
|
||||
const { StatusBar, Style } = await import('@capacitor/status-bar');
|
||||
await StatusBar.setStyle({ style: Style.Dark });
|
||||
await StatusBar.setBackgroundColor({ color: '#0d0d0d' });
|
||||
} catch(e) {}
|
||||
}
|
||||
};
|
||||
|
||||
// Auto-init if native
|
||||
if (window.NexusNative.isNative) {
|
||||
window.NexusNative.setupStatusBar();
|
||||
window.NexusNative.registerPush();
|
||||
}
|
||||
})();
|
||||
@@ -10,6 +10,7 @@
|
||||
<link rel="stylesheet" href="/pos/static/css/onboarding.css" />
|
||||
<link rel="manifest" href="/pos/static/pwa/manifest.json" />
|
||||
<meta name="theme-color" content="#F5A623" />
|
||||
<script src="/pos/static/js/native-bridge.js"></script>
|
||||
|
||||
<style>
|
||||
/* =========================================================================
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<link rel="stylesheet" href="/pos/static/css/chat.css" />
|
||||
<link rel="manifest" href="/pos/static/pwa/manifest.json" />
|
||||
<meta name="theme-color" content="#F5A623" />
|
||||
<script src="/pos/static/js/native-bridge.js"></script>
|
||||
|
||||
<style>
|
||||
/* =====================================================================
|
||||
|
||||
17
pos/www/index.html
Normal file
17
pos/www/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Nexus POS</title>
|
||||
<style>
|
||||
body { background: #0d0d0d; color: #F5A623; font-family: sans-serif;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
height: 100vh; margin: 0; }
|
||||
p { text-align: center; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Cargando Nexus POS…<br><small>Conectando al servidor</small></p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user