मुफ़्त APK बनाएँ

JavaScript ब्रिज API

Capacitor प्लगइन

ऐप में मौजूद Capacitor प्लगइन। हाथ से लिखा पेज इन्हें window.Capacitor.Plugins.<Name> के रूप में पाता है; AI से बना ऐप हर उदाहरण में बताए @/lib/appmintNative रैपर का इस्तेमाल करता है।

Capacitor.ActionSheet Capacitor#

Capacitor.Plugins.ActionSheet — showActions({ title, message, options })

उदाहरण

विकल्पों की सूची वाली नेटिव बॉटम शीट दिखाता है और बताता है कि किस पर टैप हुआ (@capacitor/action-sheet 8.1.1).

लौटाता है: Promise { index, canceled } - index वह विकल्प है जिस पर टैप हुआ; शीट खारिज होने पर canceled true होता है और index सूची के बाहर (-1) होता है। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

हर विकल्प { title, style? } होता है, जिसके style में 'DEFAULT', 'DESTRUCTIVE' या 'CANCEL'.

var ActionSheet = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ActionSheet;

async function photoMenu() {
  if (!ActionSheet) return;
  var opts = [
    { title: 'Share', style: 'DEFAULT' },
    { title: 'Edit', style: 'DEFAULT' },
    { title: 'Delete', style: 'DESTRUCTIVE' }
  ];
  var r = await ActionSheet.showActions({ title: 'Photo', message: 'Choose an action', options: opts });
  if (r.canceled || r.index < 0 || r.index >= opts.length) return;   // dismissed
  if (opts[r.index].title === 'Delete') deletePhoto();
}

AI से बने ऐप में Capacitor जैसा रैपर खारिज करने पर { index: -1 } देता है; छोटा रूप actionSheet() देता है null:

import { ActionSheet, actionSheet } from '@/lib/appmintNative';

const { index } = await ActionSheet.showActions({
  title: 'Photo',
  options: [{ title: 'Share' }, { title: 'Delete', destructive: true }],
});
if (index === 1) deletePhoto();

const i = await actionSheet('Sort by', [{ title: 'Name' }, { title: 'Date' }]);   // number | null

हटाने की पुष्टि जो सादे ब्राउज़र में भी चलती है:

async function confirmDelete(name) {
  const AS = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ActionSheet;
  if (!AS) return window.confirm('Delete ' + name + '?');
  const r = await AS.showActions({
    title: 'Delete ' + name + '?',
    options: [{ title: 'Delete', style: 'DESTRUCTIVE' }, { title: 'Keep it', style: 'CANCEL' }]
  });
  return !r.canceled && r.index === 0;
}

ध्यान दें: हमेशा index की सीमा जाँचें - किसी भी index को असली चुनाव न मानें। रैपर के विकल्प का रूप { title, destructive? } है; यह destructive को प्लगइन की 'DESTRUCTIVE' शैली से जोड़ता है।

Capacitor.App Capacitor#

Capacitor.Plugins.App — getInfo(), getState(), exitApp(), minimizeApp(), addListener(...)

उदाहरण

ऐप की पहचान और लाइफ़साइकल: नाम, पैकेज id, वर्ज़न, ऐप सामने है या नहीं, और रोकने/फिर शुरू करने के इवेंट (@capacitor/app 8.1.0).

लौटाता है: getInfo() → { name, id, build, version }; getState() → { isActive }; getLaunchUrl() → { url } या कुछ नहीं; getAppLanguage() → { value }; exitApp() / minimizeApp() → void। addListener() → remove() वाले हैंडल का Promise। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var App = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.App;
if (App) {
  App.getInfo().then(function (i) {
    document.getElementById('about').textContent = i.name + ' ' + i.version + ' (' + i.build + ')';
  });
}

रोकें और फिर शुरू करें - यूज़र के जाने पर ड्राफ़्ट सेव करें, लौटने पर रीफ़्रेश करें:

if (App) {
  App.addListener('appStateChange', function (s) {
    if (!s.isActive) saveDraft();      // went to the background
    else refreshInbox();               // back in front
  });
  App.addListener('pause', function () { console.log('paused'); });
  App.addListener('resume', function () { console.log('resumed'); });
}

AI से बने ऐप में:

import { App } from '@/lib/appmintNative';

const info = await App.getInfo();   // { name, id, build, version }
App.exitApp();                      // closes the app on Android

ध्यान दें: backButton इवेंट कभी नहीं चलता: शेल बैक बटन अपने पास रखता है (प्लगइन disableBackButtonHandler के साथ चलता है)। बैक को AppMint.setBackHandler(fn) या onBackGesture रैपर से संभालें। डीप लिंक के लिए WebToApk.getLaunchUrl() / appmint:deep-link इवेंट इस्तेमाल करें (या AI से बने ऐप में launchUrl() / onDeepLink())। minimizeApp() सिर्फ़ Android पर है। Exit बटन को आगे बढ़ने का इकलौता रास्ता कभी न बनाएँ।

Capacitor.AppLauncher Capacitor#

Capacitor.Plugins.AppLauncher — canOpenUrl({ url }), openUrl({ url })

उदाहरण

किसी लिंक (whatsapp://send?text=…, tel:, geo:, https लिंक) से दूसरा ऐप खोलता है और पूछता है कि कोई उसे संभाल सकता है या नहीं (@capacitor/app-launcher 8.0.1).

लौटाता है: canOpenUrl() → Promise { value: boolean }। openUrl() → Promise { completed: boolean } (किसी ऐप के लिंक न संभालने पर false)। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var AL = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppLauncher;

async function chatOnWhatsApp(text) {
  if (!AL) return;
  var url = 'whatsapp://send?text=' + encodeURIComponent(text);
  var can = await AL.canOpenUrl({ url: url });
  if (!can.value) { alert('WhatsApp is not installed'); return; }
  var r = await AL.openUrl({ url: url });
  if (!r.completed) alert('Could not open WhatsApp');
}

AI से बने ऐप में:

import { appLauncher } from '@/lib/appmintNative';

if (await appLauncher.canOpen('tel:+15551234567')) await appLauncher.open('tel:+15551234567');

पहले पूछे बिना मैप का लिंक खोलें:

async function openMap(query) {
  const AL = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppLauncher;
  if (!AL) { window.open('https://maps.google.com/?q=' + encodeURIComponent(query)); return; }
  const r = await AL.openUrl({ url: 'geo:0,0?q=' + encodeURIComponent(query) });
  if (!r.completed) alert('No maps app could open this');
}

ध्यान दें: Android 11+ पर ऐप सिर्फ़ उन्हीं दूसरे ऐप को "देख" सकता है जिन्हें वह घोषित करता है। बनाए गए ऐप https, geo, google.navigation, tel, mailto, sms, whatsapp, intent और upi लिंक घोषित करते हैं, इसलिए दूसरी स्कीम (जैसे spotify:) के लिए canOpenUrl का जवाब false आता है, भले ही वह ऐप इंस्टॉल हो। openUrl उनके लिए फिर भी चलता है - इसे कॉल करें और completed जाँचें। Android पर canOpenUrl पैकेज नाम ('com.whatsapp') भी लेता है, उसी दिखाई देने की सीमा के साथ।

Capacitor.AppUpdate Capacitor#

Capacitor.Plugins.AppUpdate — getAppUpdateInfo(), performImmediateUpdate(), startFlexibleUpdate(), completeFlexibleUpdate(), openAppStore()

उदाहरण

Google Play में ऐप का नया वर्ज़न जाँचता है और Play का इन-ऐप अपडेट शुरू करता है। शामिल किया गया @capawesome/capacitor-app-update (template/plugins/app-update).

लौटाता है: getAppUpdateInfo() → { currentVersionName, currentVersionCode, availableVersionCode, updateAvailability, updatePriority, immediateUpdateAllowed, flexibleUpdateAllowed, clientVersionStalenessDays?, installStatus } (वर्ज़न कोड स्ट्रिंग होते हैं; updateAvailability 2 = अपडेट उपलब्ध है)। performImmediateUpdate() / startFlexibleUpdate() → { code }: 0 ठीक, 1 रद्द, 2 विफल, 3 उपलब्ध नहीं, 4 अनुमति नहीं, 5 पहले getAppUpdateInfo() कॉल करें। openAppStore() → void। ज़रूरत: चालू करने के लिए कुछ नहीं; ऐप Google Play से इंस्टॉल किया होना चाहिए। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var AU = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppUpdate;

async function checkForUpdate() {
  if (!AU) return;
  try {
    var info = await AU.getAppUpdateInfo();          // must come first
    if (info.updateAvailability !== 2) return;       // up to date
    if (info.immediateUpdateAllowed) {
      var r = await AU.performImmediateUpdate();     // Play's full-screen update
      if (r.code === 1) console.log('user said not now');
    } else {
      await AU.openAppStore();                       // the Play listing
    }
  } catch (e) {
    console.log('Play update check failed:', e.message);  // e.g. no Play services
  }
}

फ़्लेक्सिबल अपडेट - बैकग्राउंड में डाउनलोड करें, फिर यूज़र की सहमति पर रीस्टार्ट करें:

async function flexibleUpdate() {
  if (!AU) return;
  var info = await AU.getAppUpdateInfo();
  if (info.updateAvailability !== 2 || !info.flexibleUpdateAllowed) return;
  await AU.addListener('onFlexibleUpdateStateChange', function (s) {
    if (s.installStatus === 2) console.log(s.bytesDownloaded + ' / ' + s.totalBytesToDownload);
    if (s.installStatus === 11) showRestartButton();   // 11 = DOWNLOADED
  });
  await AU.startFlexibleUpdate();
}
function restartNow() { if (AU) AU.completeFlexibleUpdate(); }

AI से बने ऐप में:

import { appUpdate } from '@/lib/appmintNative';

const info = await appUpdate.check();          // null on the web / without Play
if (info?.inPlace) await appUpdate.start();    // Android: immediate update

ध्यान दें: "अपडेट उपलब्ध है" जाँचने के लिए सिर्फ़ updateAvailability === 2 इस्तेमाल करें। रैपर का check() currentVersionName की तुलना availableVersionCode से करता है, जो Android पर कभी बराबर नहीं होते, इसलिए वहाँ उसका updateAvailable भरोसेमंद नहीं है - इसकी जगह inPlace जाँचें। start() यूज़र के रद्द करने पर भी true देता है।

Capacitor.AppwrightDocScanner Capacitor#

Capacitor.Plugins.AppwrightDocScanner — scan({ pageLimit, pdf, quality }), isSupported()

उदाहरण

Google ML Kit का डॉक्यूमेंट स्कैनर खोलता है: यूज़र एक या ज़्यादा पेजों की फ़ोटो लेता है (या इम्पोर्ट करता है), किनारे अपने आप पहचानकर सीधे किए जाते हैं, और पेज JPEG इमेज के रूप में लौटते हैं। Appwright का अपना प्लगइन (AppwrightDocScannerPlugin.kt).

लौटाता है: scan() → ऐसा Promise जो हमेशा RESOLVE होता है: सफलता पर { ok: true, pages: string[] (JPEG data URLs), pdfDataUrl?, pdfPath?, pdfError? }, यूज़र के पीछे हटने पर { ok: false, cancelled: true }, स्कैनर शुरू न हो पाने पर { ok: false, error }। isSupported() → { value: boolean } (Google Play services मौजूद हैं)। ज़रूरत: चालू करने के लिए कुछ नहीं और कैमरा अनुमति भी नहीं (स्कैनर Play services के अंदर चलता है, जो पहली बार इस्तेमाल पर अपना मॉडल डाउनलोड करता है)।

var Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightDocScanner;

async function scanReceipt() {
  if (!Scanner) { alert('Scanning is not available here'); return; }
  var s = await Scanner.isSupported();
  if (!s.value) { alert('This phone has no Google Play services'); return; }
  var r = await Scanner.scan({ pageLimit: 1, pdf: false, quality: 0.8 });
  if (r.cancelled) return;
  if (!r.ok) { alert('Scanner error: ' + r.error); return; }
  document.getElementById('preview').src = r.pages[0];
}

pageLimit 0 = कोई सीमा नहीं। quality JPEG के लिए 0.1-1 है। pdf: true के साथ स्कैनर PDF भी लिखता है: pdfDataUrl वह data:application/pdf;base64,… URL के रूप में है जिसे पेज डाउनलोड, अपलोड या दिखा सकता है, और pdfPath ऐप के कैश फ़ोल्डर में उसकी कॉपी है। PDF न पढ़ी जा सके तो पेज फिर भी लौटते हैं और pdfError कारण बताता है।

AI से बने ऐप में (रद्द करने, त्रुटि, या वेब पर null):

import { docScanner, can } from '@/lib/appmintNative';

if (can('docScanner') !== 'none') {
  const res = await docScanner.scan({ pageLimit: 5, pdf: true });
  if (res) setPages(res.pages);          // res.pdfPath when pdf: true
}

कई पेज स्कैन करें और PDF दें:

async function scanContract() {
  const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightDocScanner;
  if (!Scanner) return;
  const r = await Scanner.scan({ pageLimit: 0, pdf: true, quality: 0.9 });
  if (!r.ok) { if (!r.cancelled) alert('Scanner error: ' + r.error); return; }
  if (r.pdfDataUrl) {
    const a = document.createElement('a');
    a.href = r.pdfDataUrl; a.download = 'contract.pdf'; a.click();
  } else if (r.pdfError) console.warn('PDF not made:', r.pdfError);
  console.log(r.pages.length + ' pages scanned');
}

ध्यान दें: पेज पूरे data URL होते हैं और बड़े हो सकते हैं - कई को localStorage में सेव करने से पहले उन्हें छोटा करें। pdfDataUrl इस्तेमाल करें, pdfPath नहीं - डिवाइस का फ़ाइल पाथ ऐसा URL नहीं है जिसे पेज लोड कर सके। जो पेज पढ़ा न जा सके उसे छोड़ दिया जाता है; बाकी फिर भी लौटते हैं।

Capacitor.AppwrightGallery Capacitor#

Capacitor.Plugins.AppwrightGallery — save({ source, fileName, album, kind })

उदाहरण

फ़ोटो या वीडियो को फ़ोन की गैलरी में सेव करता है (Pictures/<album> या Movies/<album>)। ऐप शेल का अपना प्लगइन (AppwrightGalleryPlugin.kt).

लौटाता है: सेव किए गए आइटम का { uri } Promise। code के साथ reject होता है: bad-source, download-failed, permission-denied (Android 7-9, स्टोरेज से मना) या failed। ज़रूरत: चालू करने के लिए कुछ नहीं; Android 10+ पर कोई अनुमति नहीं (Android 7-9 पहली बार स्टोरेज माँगता है)।

const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;

async function saveCard(canvas) {
  const dataUrl = canvas.toDataURL('image/png');
  if (!Gallery) { const a = document.createElement('a'); a.href = dataUrl; a.download = 'card.png'; a.click(); return; }
  try {
    await Gallery.save({ source: dataUrl, fileName: 'birthday-card.png', album: 'Cards' });
    toast('Saved to your gallery');
  } catch (e) {
    toast('Could not save: ' + e.message);
  }
}

अपने सर्वर से एक वीडियो को उसकी अपनी एल्बम में सेव करें, हर विफलता कोड के लिए एक संदेश के साथ:

const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;

async function saveClip(url) {
  if (!Gallery) { window.open(url, '_blank'); return; }
  try {
    await Gallery.save({ source: url, fileName: 'highlight.mp4', album: 'Highlights', kind: 'video' });
    toast('Video saved to Movies/Highlights');
  } catch (e) {
    if (e.code === 'download-failed') toast('Could not download the video. Check your connection.');
    else if (e.code === 'permission-denied') toast('Allow storage access to save videos.');
    else toast('Could not save: ' + e.message);
  }
}

यूज़र की एडिट की हुई फ़ोटो को Blob के रूप में (जैसे canvas.toBlob से) सेव करें, पहले उसे data: URL में बदलकर:

const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;

function blobToDataUrl(blob) {
  return new Promise((resolve, reject) => {
    const r = new FileReader();
    r.onload = () => resolve(r.result);
    r.onerror = () => reject(r.error);
    r.readAsDataURL(blob);
  });
}

async function saveEditedPhoto(canvas) {
  if (!Gallery) return;
  const blob = await new Promise((res) => canvas.toBlob(res, 'image/jpeg', 0.92));
  const { uri } = await Gallery.save({ source: await blobToDataUrl(blob), fileName: 'edit-' + Date.now() + '.jpg', album: 'My Edits' });
  console.log('saved as', uri);
}

ध्यान दें: source एक data: URL, http(s) URL या content:///file:// URI है; kind ('image'/'video') छोड़ने पर MIME टाइप से पढ़ा जाता है। AI से बने ऐप saveToGallery() इस्तेमाल करते हैं, यहाँ से @/lib/appmintNative.

Capacitor.AppwrightHaptics Capacitor#

Capacitor.Plugins.AppwrightHaptics

उदाहरण

AppMint का अपना प्लगइन, बेहतर वाइब्रेशन पैटर्न के लिए: बीट की सूची, जिनमें से हर एक का अपना शुरू होने का समय, लंबाई और तेज़ी होती है।

लौटाता है: play({ events }) का नतीजा { ok: true } या { ok: false, error } होता है ('unsupported' = वाइब्रेटर नहीं है, 'empty' = कोई इवेंट नहीं, या सिस्टम का संदेश)। यह कभी reject नहीं होता। isSupported() का नतीजा { value: true/false } है। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप वाइब्रेशन अनुमति घोषित करता है, चाहे चरण 4 (Access) में Vibrate टिक हो या नहीं। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

हर इवेंट { at, duration, intensity, sharpness } है: at = ms में शुरुआत, duration = ms में लंबाई (20 से कम होने पर 30 ms का टैप बन जाता है), intensity = 0-1 (डिफ़ॉल्ट 0.8)। sharpness स्वीकार होता है लेकिन Android पर अनदेखा किया जाता है।

var AH = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.AppwrightHaptics : null;

async function heartbeat() {
  if (!AH) return false;
  var r = await AH.play({
    events: [
      { at: 0,   intensity: 0.8 },
      { at: 140, intensity: 0.5 },
      { at: 700, intensity: 0.8 },
      { at: 840, intensity: 0.5 }
    ]
  });
  if (!r.ok) console.log('pattern not played:', r.error);
  return r.ok;
}

document.getElementById('like').addEventListener('click', heartbeat);

जिन फ़ोन में वाइब्रेटर नहीं है उन पर बटन छिपाएँ:

(async function () {
  var btn = document.getElementById('feel-it');
  var ok = false;
  if (AH) { try { ok = (await AH.isSupported()).value; } catch (e) {} }
  btn.hidden = !ok;
})();

सफल काम पर तेज़ डबल टैप चलाएँ, और न चल पाए तो बताएँ:

async function successBuzz() {
  const AH = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightHaptics;
  if (!AH) return;
  const r = await AH.play({ events: [{ at: 0, duration: 40, intensity: 1 }, { at: 120, duration: 40, intensity: 0.6 }] });
  if (!r.ok && r.error === 'unsupported') console.log('this phone has no vibrator');
}

ध्यान दें: तेज़ी (strength) सिर्फ़ उन फ़ोन पर काम करती है जिनमें amplitude कंट्रोल है; दूसरे फ़ोन टाइमिंग को एक तय तेज़ी पर रखते हैं। अगर सिस्टम वाइब्रेशन से मना कर दे तो play का जवाब { ok: false, error: '<the system message>' } आता है। AI से बने ऐप @/lib/appmintNative से hapticPlay इस्तेमाल करें, जिसमें नाम वाले पैटर्न भी हैं।

Capacitor.AppwrightLiveProgress Capacitor#

Capacitor.Plugins.AppwrightLiveProgress — start / update / end

उदाहरण

AppMint का अपना Android प्लगइन (इसका JS नाम AppwrightLiveProgress है) जो स्टिकी, बिना आवाज़ वाला, लाइव अपडेट होने वाला स्टेटस नोटिफ़िकेशन (प्रोग्रेस बार, स्पिनर या चलती घड़ी) दिखाता है, और टैप करने पर एक रूट खोलता है।

लौटाता है: start(opts) / update(opts) → Promise<{ ok: true, id }>, या कुछ पोस्ट हुए बिना { ok: false, error } - नोटिफ़िकेशन की अनुमति न होने पर 'permission' (Android 13+: अभी दी नहीं गई, या ऐप के लिए बंद है), यूज़र के "Live status" श्रेणी बंद करने पर 'channel_disabled'; end({ id }) → Promise<void>। ज़रूरत: Android ऐप और नोटिफ़िकेशन अनुमति (Android 13+)। वेब पर उपलब्ध नहीं।

AI से बने ऐप में रैपर liveProgress इस्तेमाल करें, यहाँ से @/lib/appmintNative:

import { liveProgress } from '@/lib/appmintNative';
await liveProgress.start({ id: 'order', title: 'Order #42', text: 'Being prepared', indeterminate: true });
await liveProgress.update({ id: 'order', title: 'Order #42', text: 'On the way', progress: 0.6, route: '/orders/42' });
await liveProgress.end('order');

हाथ से लिखे पेज में:

async function showDelivery(step, total) {
  const P = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
  if (!P) return;                                   // not in the Android app
  if (window.Notification && Notification.permission !== 'granted') {
    if (await Notification.requestPermission() !== 'granted') return;
  }
  const r = await P.update({
    id: 'delivery',
    title: 'Your delivery',
    text: 'Stop ' + step + ' of ' + total,
    progress: step / total,                         // 0–1; or indeterminate: true
    route: '/track'                                 // opened when the card is tapped
  });
  if (!r.ok) console.warn('live card not posted:', r.error);
}

async function deliveryDone() {
  const P = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
  if (P) await P.end({ id: 'delivery' });
}

वर्कआउट टाइमर: startedAt कार्ड को अपने आप ऊपर गिनवाता है, इसलिए इसे एक बार पोस्ट किया जाता है और वर्कआउट रुकने पर ख़त्म किया जाता है:

const Live = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
let workoutStart = 0;

async function startWorkout(name) {
  workoutStart = Date.now();
  if (!Live) return;
  const r = await Live.start({ id: 'workout', title: name, text: 'Workout in progress', startedAt: workoutStart, route: '/workout' });
  if (!r.ok && r.error === 'channel_disabled') {
    showHint('Turn on "Live status" in this app\'s notification settings to see the timer.');
  }
}

async function stopWorkout() {
  if (Live) await Live.end({ id: 'workout' });
  saveWorkout({ durationMs: Date.now() - workoutStart });
}

विकल्प: id (डिफ़ॉल्ट 'live'), title, text, progress (0-1, बार न चाहिए तो छोड़ दें), indeterminate, startedAt (epoch ms, चलती घड़ी दिखाता है), route.

ध्यान दें: start और update एक ही काम करते हैं (उस id वाला कार्ड पोस्ट करें या बदलें)। कार्ड को स्वाइप करके हटाया नहीं जा सकता - हमेशा end कॉल करें। पहले अनुमति माँगें: Android 13+ पर इसके बिना start का जवाब error: 'permission' आता है और कुछ पोस्ट नहीं होता।

Capacitor.AppwrightSystemPalette Capacitor#

Capacitor.Plugins.AppwrightSystemPalette — get()

उदाहरण

फ़ोन के Material You रंग लौटाता है (वह पैलेट जो Android 12+ वॉलपेपर से बनाता है), ताकि ऐप सिस्टम ऐप से मेल खा सके। AppMint का अपना प्लगइन (AppwrightSystemPalettePlugin.kt).

लौटाता है: Android 12 से नीचे Promise { available: false }, वरना { available: true, accent1, accent2, accent3, neutral1, neutral2 } - हर एक टोन से hex रंग का ऑब्जेक्ट, टोन '0', '10', '50', '100' … '900', '1000' के साथ (जैसे accent1['600'] === '#3F5F90')। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Palette = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightSystemPalette;

async function useWallpaperColours() {
  if (!Palette) return;
  var p = await Palette.get();
  if (!p.available) return;                 // keep the app's own colours
  var root = document.documentElement.style;
  root.setProperty('--accent', p.accent1['600']);
  root.setProperty('--surface', p.neutral1['50']);
}
useWallpaperColours();

AI से बने ऐप में:

import { systemPalette } from '@/lib/appmintNative';

const p = await systemPalette();
if (p.available && p.accent1) document.documentElement.style.setProperty('--accent', p.accent1['600']);

सिस्टम थीम से मेल खाने के लिए हल्के या गहरे टोन चुनें, और वॉलपेपर बदलकर यूज़र के लौटने पर पैलेट दोबारा पढ़ें:

var Palette = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightSystemPalette;
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)');

async function applyPalette() {
  if (!Palette) return;
  var p = await Palette.get();
  if (!p.available) return;
  var dark = darkQuery.matches;
  var s = document.documentElement.style;
  s.setProperty('--accent', p.accent1[dark ? '200' : '600']);
  s.setProperty('--on-accent', p.accent1[dark ? '800' : '0']);
  s.setProperty('--bg', p.neutral1[dark ? '900' : '10']);
  s.setProperty('--text', p.neutral1[dark ? '100' : '900']);
}

darkQuery.addEventListener('change', applyPalette);
document.addEventListener('visibilitychange', function () {
  if (document.visibilityState === 'visible') applyPalette();
});
applyPalette();

ध्यान दें: पैलेट के रंग लगाने से पहले टेक्स्ट का कंट्रास्ट जाँचें - वॉलपेपर का टोन आपके बैकग्राउंड पर अच्छा पढ़ा जाए, इसकी गारंटी नहीं है। ब्राउज़र वॉलपेपर रंग नहीं देते: वेब पर रैपर { available: false } लौटाता है। यूज़र के वॉलपेपर बदलने पर रंग बदलते हैं; वापस आने पर get() फिर कॉल करें।

Capacitor.AppwrightWidget Capacitor#

Capacitor.Plugins.AppwrightWidget — set(card), clear(), placedCount(), requestPin()

उदाहरण

ऐप का होम-स्क्रीन विजेट भरता है: एक कार्ड जिसमें शीर्षक, बड़ी वैल्यू, छह लाइनें तक, आपके रंग और टैप का रूट होता है। कार्ड फ़ोन पर सेव होता है और रीबूट के बाद भी दिखता है। AppMint का अपना प्लगइन (AppwrightWidgetPlugin.kt).

लौटाता है: set({ title?, value?, lines?, route?, bg?, ink?, accent? }) → Promise { ok: true, placed } (placed = होम स्क्रीन पर अभी लगे विजेट)। clear() → void। placedCount() → { value }। requestPin() → { value: boolean } (true जब लॉन्चर की "विजेट जोड़ें" शीट खुली)। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप विजेट घोषित करता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Widget = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightWidget;

async function updateWidget(tasks) {
  if (!Widget) return;
  await Widget.set({
    title: 'Today',
    value: tasks.length + ' tasks',
    lines: tasks.slice(0, 6).map(function (t) { return t.title; }),
    route: '/today',                 // opened when the widget is tapped
    bg: '#0B0F1A', ink: '#FFFFFF', accent: '#22D3EE'
  });
}

इसे लगाने का सुझाव दें (सिर्फ़ तब जब अभी कोई न लगा हो):

async function offerWidget() {
  if (!Widget) return;
  var n = (await Widget.placedCount()).value;
  if (n > 0) return;
  var r = await Widget.requestPin();
  if (!r.value) alert('Long-press the home screen, tap Widgets and pick this app.');
}

AI से बने ऐप में:

import { widget } from '@/lib/appmintNative';

await widget.set({ title: 'Today', value: '3 tasks', lines: ['Gym', 'Call mum'], route: '/today' });
if ((await widget.placedCount()) === 0) await widget.requestPin();

ध्यान दें: रंग hex स्ट्रिंग होते हैं; खाली रंग पर गहरा कार्ड और सियान वैल्यू इस्तेमाल होती है। टैप करने पर ऐप route पर डीप लिंक के रूप में खुलता है (इसे WebToApk.getLaunchUrl() या appmint:deep-link इवेंट से पढ़ें)। किसी भी set() से पहले विजेट "Nothing to show yet" कहता है; clear() उसे उसी स्थिति में लौटाता है। ब्राउज़र में can('widget') है 'none'.

Capacitor.Badge Capacitor#

Capacitor.Plugins.Badge — the launcher-icon count

उदाहरण

Badge प्लगइन (capawesome) जो ऐप के लॉन्चर आइकन पर नंबर लगाता है।

लौटाता है: Promise: set({ count }), clear(), increase(), decrease() → void; get() → { count }; isSupported() → { isSupported }। Android प्लगइन में अनुमति के तरीके नहीं हैं। ज़रूरत: Android पर कुछ नहीं। वेब पर उपलब्ध नहीं।

AI से बने ऐप में रैपर badge इस्तेमाल करें, यहाँ से @/lib/appmintNative:

import { badge } from '@/lib/appmintNative';
await badge.set(3);
await badge.clear();

हाथ से लिखे पेज में:

async function setUnread(count) {
  const B = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Badge;
  if (!B) return false;                       // not inside the app
  try {
    const s = await B.isSupported();
    if (!s.isSupported) return false;         // this launcher shows no badges
    if (count > 0) await B.set({ count: count });
    else await B.clear();
    return true;
  } catch (e) {
    return false;
  }
}

window.addEventListener('appmint:push', function () {
  const inbox = JSON.parse(window.WebToApk ? WebToApk.getPushInbox() : '[]');
  setUnread(inbox.filter(function (m) { return !m.read; }).length);
});

आइटम आने और पढ़े जाने पर गिनती बढ़ाएँ और घटाएँ:

const B = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Badge;
async function onNewMessage() { if (B) await B.increase(); }
async function onMessageRead() { if (B) await B.decrease(); }
async function showCurrent() {
  if (!B) return;
  const { count } = await B.get();
  console.log('badge shows', count);
}

ध्यान दें: Android पर दिखावट लॉन्चर पर निर्भर है (नंबर, डॉट, या कुछ नहीं)। ऐप में navigator.setAppBadge(n) उसी बैज पर लिखता है (यह सिर्फ़ उन लॉन्चर पर होता है जो गिनती दिखा सकते हैं)।

Capacitor.BarcodeScanner Capacitor#

Capacitor.Plugins.BarcodeScanner — scan, startScan, readBarcodesFromImage, isSupported

उदाहरण

@capacitor-mlkit/barcode-scanning API के साथ QR और बारकोड स्कैन - ऐप शेल का अपना प्लगइन (BarcodeScannerPlugin.kt), वही Google कोड स्कैनर जो AppMint.scanCode() में है। पुराने @capacitor-community/barcode-scanner कॉल (startScan() जो { hasContent, content }, checkPermission, prepare, hideBackground देते हैं) यही नाम इस्तेमाल करते हैं और वे भी चलते हैं।

लौटाता है: scan({ formats?, autoZoom? }) → { barcodes: [{ rawValue, displayValue, format, valueType, bytes?, cornerPoints?, urlBookmark?, wifi?, email?, phone?, sms?, geoPoint?, contactInfo?, calendarEvent?, driverLicense? }] } (यूज़र के पीछे हटने पर "scan canceled." के साथ reject); readBarcodesFromImage({ path, formats? }) → { barcodes }; isSupported() → { supported }; isGoogleBarcodeScannerModuleAvailable() → { available }; installGoogleBarcodeScannerModule() (प्रोग्रेस googleBarcodeScannerModuleInstallProgress के रूप में); checkPermissions() / requestPermissions() → { camera }; openSettings()। format है 'QR_CODE', 'EAN_13', 'CODE_128'… ज़रूरत: चालू करने के लिए कुछ नहीं और कैमरा अनुमति भी नहीं - Google का स्कैनर अपनी स्क्रीन खुद बनाता है (Play services इसे पहली बार इस्तेमाल पर डाउनलोड करता है)। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;

scanBtn.onclick = async () => {
  if (!Scanner) return;
  try {
    const { barcodes } = await Scanner.scan({ formats: ['QR_CODE'] });
    const code = barcodes[0];
    if (code.valueType === 'URL') location.href = code.urlBookmark.url;
    else resultBox.textContent = code.displayValue;
  } catch (e) {
    if (e.message !== 'scan canceled.') alert(e.message);
  }
};

प्रोडक्ट बारकोड से कीमत खोजना, उस लिसनर शैली के साथ (startScan + barcodesScanned) जो ML Kit ऐप पहले से इस्तेमाल करते हैं:

const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;

async function scanProduct() {
  const listener = await Scanner.addListener('barcodesScanned', async ({ barcodes }) => {
    await listener.remove();
    await Scanner.stopScan();
    const ean = barcodes[0].rawValue;
    const res = await fetch('https://api.example.com/products/' + encodeURIComponent(ean));
    priceBox.textContent = res.ok ? (await res.json()).price : 'Not found';
  });
  await Scanner.startScan({ formats: ['EAN_13', 'EAN_8', 'UPC_A', 'UPC_E'] });
}

यूज़र के पास पहले से मौजूद फ़ोटो से QR कोड पढ़ें:

const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
const Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;

async function qrFromGallery() {
  const photo = await Camera.getPhoto({ source: 'PHOTOS', resultType: 'uri', quality: 90 });
  const { barcodes } = await Scanner.readBarcodesFromImage({ path: photo.path, formats: ['QR_CODE'] });
  return barcodes.length ? barcodes[0].rawValue : null;
}

ध्यान दें: अपस्ट्रीम का startScan() पारदर्शी पेज के पीछे कैमरा का लाइव प्रीव्यू दिखाता है और stopScan() तक स्कैन करता रहता है; यहाँ यह स्कैनर स्क्रीन खोलता है, पहला कोड barcodeScanned / barcodesScanned चलाता है, और सेशन ख़त्म हो जाता है (कम्युनिटी कोड के लिए कॉल फिर { hasContent, content, format } देता है; बंद किया गया स्कैनर { hasContent: false } देता है)। टॉर्च और ज़ूम उसी प्रीव्यू के हैं, इसलिए isTorchAvailable() का जवाब false है और टॉर्च/ज़ूम सेट करने वाले reject होते हैं - स्कैनर स्क्रीन का अपना फ़्लैशलाइट बटन है। ऐप के पास कैमरा अनुमति बिल्कुल न हो तो checkPermissions() का जवाब granted है (स्कैनर को इसकी ज़रूरत नहीं); जो ऐप कैमरा भी इस्तेमाल करता है उसे असली स्थिति मिलती है। AI से बने ऐप scanCode() इस्तेमाल करते हैं, यहाँ से @/lib/appmintNative.

Capacitor.Browser Capacitor#

Capacitor.Plugins.Browser — open({ url, toolbarColor }), close(), addListener('browserFinished')

उदाहरण

वेब पेज को ऐप के अंदर ब्राउज़र टैब (Chrome Custom Tabs) में खोलता है, ताकि यूज़र शर्तें, डॉक्स या साइन-इन पेज पढ़कर एक इशारे में लौट आए (@capacitor/browser 8.0.3).

लौटाता है: open() / close() → Promise void। इवेंट: browserFinished (यूज़र ने टैब बंद किया) और browserPageLoaded। ज़रूरत: कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है (Custom Tabs सपोर्ट करने वाला ब्राउज़र, जैसे Chrome, इंस्टॉल होना चाहिए)। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Browser = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Browser;

async function openTerms() {
  if (!Browser) return;
  var h = await Browser.addListener('browserFinished', function () {
    console.log('user closed the terms');
    h.remove();
  });
  await Browser.open({ url: 'https://example.com/terms', toolbarColor: '#0B0F1A' });
}

AI से बने ऐप में (वेब पर नया टैब):

import { browser } from '@/lib/appmintNative';

const off = browser.onClosed(() => refreshAccount());
await browser.open('https://example.com/terms', { toolbarColor: '#0B0F1A' });
// call off() when you no longer care

लिंक खोलें, और साइन-इन की वापसी पेज तक पहुँचने पर टैब बंद करें:

var Browser = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Browser;

async function openHelp() {
  if (!Browser) { window.open('https://example.com/help', '_blank'); return; }
  try {
    await Browser.open({ url: 'https://example.com/help' });
  } catch (e) {
    alert('Could not open the page: ' + e.message);
  }
}

window.addEventListener('appmint:deep-link', function () {
  if (Browser) Browser.close().catch(function () {});
});

ध्यान दें: url खाली नहीं होना चाहिए। toolbarColor hex रंग है; ग़लत रंग को अनदेखा किया जाता है। close() इस प्लगइन वर्ज़न में Android पर भी चलता है (यह टैब की होस्ट एक्टिविटी बंद करता है) - साइन-इन लिंक के ऐप में लौटने के बाद काम का है। टैब एक अलग ब्राउज़र है: यह ऐप की कुकीज़ या localStorage.

Capacitor.Calendar Capacitor#

Capacitor.Plugins.Calendar — createEvent, findEvents, deleteEvent, listCalendars, openCalendar

उदाहरण

फ़ोन के अपने कैलेंडर (Android CalendarContract) में इवेंट जोड़ता है, खोजता है और हटाता है, और किसी तारीख पर कैलेंडर ऐप खोलता है। शामिल किया गया @capacitor/calendar (template/plugins/calendar).

लौटाता है: createEvent() → { id }; findEvents() → { events: [{ id, title, location?, notes?, startDate, endDate, isAllDay, calendarId, calendarName?, attendees? }] }; listCalendars() → { calendars: [{ id, name, displayName?, isPrimary }] }; deleteEvent(), openCalendar() → void। तारीखें epoch मिलीसेकंड में हैं। ज़रूरत: बिल्ड करते समय चरण 4 (Access) में Calendar टिक करें। HTML, ZIP और AI से बने ऐप के लिए, जब आपकी फ़ाइलों में बिल्कुल इसी तरह लिखा Calendar.<method>( कॉल (जैसा नीचे है) या रैपर का calendar.createEvent( होता है तो बिल्ड कैलेंडर अनुमति अपने आप भी जोड़ देता है। प्लगइन पहली बार इस्तेमाल पर यूज़र से कैलेंडर एक्सेस माँगता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Calendar = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Calendar;

async function addDentist() {
  if (!Calendar) return;
  var start = new Date('2026-10-02T10:00:00').getTime();
  try {
    var r = await Calendar.createEvent({
      title: 'Dentist', startDate: start, endDate: start + 60 * 60 * 1000,
      location: 'Main St 5', notes: 'Bring the card', isAllDay: false,
      firstReminderMinutes: 30
    });
    console.log('event id', r.id);
  } catch (e) {
    // e.code: OS-PLUG-CLDR-0020 permission denied, -0001 bad arguments
    alert('Could not add the event: ' + e.message);
  }
}

इस हफ़्ते के इवेंट पढ़ें, एक हटाएँ, कैलेंडर खोलें:

async function thisWeek() {
  if (!Calendar) return;
  var now = Date.now();
  var found = await Calendar.findEvents({ startDate: now, endDate: now + 7 * 864e5 });
  found.events.forEach(function (ev) { console.log(ev.title, new Date(ev.startDate)); });
  if (found.events.length) await Calendar.deleteEvent({ id: found.events[0].id });
  await Calendar.openCalendar({ date: now });
}

AI से बने ऐप में (वेब पर createEvent एक .ics फ़ाइल डाउनलोड करता है; पढ़ने पर लौटता है []):

import { calendar } from '@/lib/appmintNative';

if ((await calendar.requestPermission()) === 'granted') {
  const id = await calendar.createEvent({ title: 'Dentist', start: new Date('2026-10-02T10:00'), end: new Date('2026-10-02T11:00') });
  const week = await calendar.listEvents({ from: Date.now(), to: Date.now() + 7 * 864e5 });
  if (id) await calendar.deleteEvent(id);
  await calendar.openCalendar(new Date());
}

ध्यान दें: ऐप में कैलेंडर अनुमति न हो तो कोई डायलॉग नहीं आता और हर इवेंट कॉल reject होता है (अनुमति नहीं है); जो यूज़र मना कर दे उसे OS-PLUG-CLDR-0020 मिलता है। recurrence: { frequency: 'daily' | 'weekly' | 'monthly' | 'yearly', interval?, count?, endDate? } दोहराने वाला इवेंट बनाता है। createEventInteractively({ title, startDate, endDate }) इसकी जगह कैलेंडर ऐप का अपना एडिटर खोलता है (कोई id वापस नहीं आती)। रैपर exception फेंकने की जगह null / [] / false लौटाता है।

Capacitor.Camera Capacitor#

Capacitor.Plugins.Camera

उदाहरण

आधिकारिक Capacitor Camera प्लगइन, जो ऐप में शामिल है: कैमरे से फ़ोटो खींचें या गैलरी से फ़ोटो चुनें।

लौटाता है: Promise। getPhoto(opts) → { dataUrl | base64String | webPath, format, saved } (कौन-सा फ़ील्ड resultType पर निर्भर है), और यूज़र के रद्द करने पर REJECT होता है; pickImages(opts) → { photos: [{ webPath, format }] }; checkPermissions() / requestPermissions({ permissions }) → { camera, photos }। ज़रूरत: चरण 4 (Access) में Camera टिक करें। HTML, ZIP और AI से बने ऐप के लिए, जब आपकी फ़ाइलों में बिल्कुल इसी तरह लिखा Camera.getPhoto( (जैसा नीचे है), वीडियो के साथ getUserMedia, या <input capture> होता है तो बिल्ड कैमरा अनुमति अपने आप भी जोड़ देता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

फ़ोटो खींचें और दिखाएँ।

async function takePhoto() {
  var Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
  if (!Camera) { showMessage('Open the app to use the camera.'); return; }
  try {
    var perm = await Camera.requestPermissions({ permissions: ['camera'] });
    if (perm.camera !== 'granted') { showMessage('Camera permission was refused.'); return; }

    var photo = await Camera.getPhoto({
      source: 'CAMERA',          // 'CAMERA' | 'PHOTOS' | 'PROMPT'
      resultType: 'dataUrl',     // 'dataUrl' | 'base64' | 'uri'
      quality: 80,
      direction: 'REAR',         // 'REAR' | 'FRONT'
      correctOrientation: true,
      saveToGallery: false
    });
    document.getElementById('photo').src = photo.dataUrl;
  } catch (err) {
    // The user closed the camera (or no camera app). Nothing to do.
  }
}

गैलरी से 5 फ़ोटो तक चुनें।

async function choosePhotos() {
  var Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
  if (!Camera) return;
  try {
    var result = await Camera.pickImages({ quality: 80, limit: 5 });
    result.photos.forEach(function (p) {
      var img = document.createElement('img');
      img.src = p.webPath;       // a URL the page can load
      document.getElementById('gallery').appendChild(img);
    });
  } catch (err) { /* cancelled */ }
}

AI से बने ऐप में रैपर इस्तेमाल करें, जो वेब पर भी चलता है (और रद्द करने पर exception फेंकने की जगह null देता है):

import { camera } from '@/lib/appmintNative';
const photo = await camera.take({ source: 'camera' });

ध्यान दें: pickImages को कैमरा अनुमति नहीं चाहिए। अगर ऐप में कैमरा अनुमति नहीं है (बॉक्स बंद था और बिल्ड को कोई कैमरा कॉल नहीं मिली), तो कैमरा अनुमति बिना पूछे मना हो जाती है। <input type="file" accept="image/*" capture> भी कैमरा खोलता है। कैमरा संवेदनशील है: इसे अपने Play Data safety फ़ॉर्म में बताएँ।

Capacitor.CapacitorBarcodeScanner Capacitor#

Capacitor.Plugins.CapacitorBarcodeScanner — scanBarcode({ hint })

उदाहरण

आधिकारिक @capacitor/barcode-scanner API के साथ एक कॉल में QR / बारकोड स्कैन - ऐप शेल का अपना प्लगइन (CapacitorBarcodeScannerPlugin.kt), वही Google कोड स्कैनर जो AppMint.scanCode() में है। npm पैकेज (CapacitorBarcodeScanner.scanBarcode({ hint: CapacitorBarcodeScannerTypeHint.ALL })) के लिए लिखा कोड बिना बदलाव के चलता है।

लौटाता है: scanBarcode({ hint, scanInstructions?, cameraDirection?, scanOrientation? }) → { ScanResult, format }। hint / format पैकेज के नंबर हैं: 0 QR_CODE, 1 AZTEC, 2 CODABAR, 3 CODE_39, 4 CODE_93, 5 CODE_128, 6 DATA_MATRIX, 8 ITF, 9 EAN_13, 10 EAN_8, 11 PDF_417, 14 UPC_A, 15 UPC_E, 17 ALL। यूज़र के स्कैनर बंद करने पर कोड OS-PLUG-BARC-0006 के साथ reject होता है। ज़रूरत: चालू करने के लिए कुछ नहीं और कैमरा अनुमति भी नहीं - Google का स्कैनर अपनी स्क्रीन खुद बनाता है (Play services इसे पहली बार इस्तेमाल पर डाउनलोड करता है)। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;

ticketBtn.onclick = async () => {
  if (!Scanner) return;
  try {
    const { ScanResult } = await Scanner.scanBarcode({ hint: 0 });   // QR codes only
    const ok = await fetch('/api/tickets/check?code=' + encodeURIComponent(ScanResult)).then((r) => r.ok);
    statusBox.textContent = ok ? 'Valid ticket' : 'Unknown ticket';
  } catch (e) {
    if (e.code !== 'OS-PLUG-BARC-0006') alert(e.message);
  }
};

कोई भी कोड स्वीकार करें, और यूज़र को बताएँ कि वह किस तरह का था:

const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
const NAMES = { 0: 'QR code', 5: 'Code 128', 9: 'EAN-13', 10: 'EAN-8', 14: 'UPC-A', 15: 'UPC-E' };

async function scanAnything() {
  const { ScanResult, format } = await Scanner.scanBarcode({ hint: 17 });
  return (NAMES[format] || 'Barcode') + ': ' + ScanResult;
}

ऐसी rejection संभालें जो यूज़र का स्कैनर बंद करना न हो:

const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;

async function scanProduct() {
  if (!Scanner) { alert('Scanning works only inside the app'); return null; }
  try {
    const { ScanResult } = await Scanner.scanBarcode({ hint: 9 });   // EAN-13
    return ScanResult;
  } catch (e) {
    if (e.code === 'OS-PLUG-BARC-0006') return null;                 // user closed the scanner
    alert('Scan failed: ' + e.message);
    return null;
  }
}

ध्यान दें: scanInstructions, scanButton, cameraDirection और scanOrientation अपस्ट्रीम की अपनी कैमरा स्क्रीन की शैली तय करते हैं और Google के स्कैनर पर इनका कोई असर नहीं होता (हमेशा पीछे वाला कैमरा)। MAXICODE, RSS_14, RSS_EXPANDED और UPC_EAN_EXTENSION को hint के रूप में सपोर्ट नहीं किया जाता (OS-PLUG-BARC-0008 के साथ reject); 17 (ALL) हर सपोर्टेड टाइप स्कैन करता है। AI से बने ऐप scanCode() इस्तेमाल करते हैं, यहाँ से @/lib/appmintNative.

Capacitor.CapacitorSQLite Capacitor#

Capacitor.Plugins.CapacitorSQLite — createConnection, open, execute, query, run, executeSet, close

उदाहरण

फ़ोन पर असली SQLite डेटाबेस, @capacitor-community/sqlite API के साथ। @capacitor-community/sqlite (template/plugins/sqlite) शामिल किया गया है, जो Android के अपने SQLite पर चलता है। npm पैकेज (new SQLiteConnection(CapacitorSQLite)) के लिए लिखा कोड बिना बदलाव के चलता है; हाथ से लिखा पेज प्लगइन ऑब्जेक्ट को सीधे कॉल करता है, जैसा नीचे दिखाया है।

लौटाता है: createConnection({ database, version, encrypted: false, mode: 'no-encryption', readonly: false }), open({ database }), close({ database }), closeConnection({ database }) → void; execute({ database, statements }) → { changes: { changes } }; run({ database, statement, values }) → { changes: { changes, lastId } }; query({ database, statement, values }) → { values: [rows] }; executeSet({ database, set: [{ statement, values }] }) → { changes }; isDBExists({ database }) / isDBOpen({ database }) → { result }; beginTransaction, commitTransaction, rollbackTransaction, isTransactionActive({ database }); deleteDatabase({ database }); बैकअप के लिए exportToJson / importFromJson। ज़रूरत: चालू करने के लिए कुछ नहीं और कोई अनुमति नहीं। डेटाबेस ऐप के निजी स्टोरेज में रहता है और ऐप अपडेट के बाद भी बना रहता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
const database = 'notes';

async function openNotes() {
  if (!DB) return false;
  await DB.createConnection({ database, version: 1, encrypted: false, mode: 'no-encryption', readonly: false });
  await DB.open({ database, readonly: false });
  await DB.execute({ database, statements:
    'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT NOT NULL, at INTEGER);' });
  return true;
}

async function addNote(text) {
  const r = await DB.run({ database, statement: 'INSERT INTO notes (text, at) VALUES (?, ?);', values: [text, Date.now()] });
  return r.changes.lastId;
}

async function listNotes() {
  const r = await DB.query({ database, statement: 'SELECT id, text, at FROM notes ORDER BY at DESC;', values: [] });
  return r.values || [];
}

कई राइट जो सभी हों या कोई नहीं - एक ट्रांज़ैक्शन के साथ executeSet:

const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;

async function moveMoney(database, fromId, toId, amount) {
  await DB.executeSet({ database, transaction: true, set: [
    { statement: 'UPDATE accounts SET balance = balance - ? WHERE id = ?;', values: [amount, fromId] },
    { statement: 'UPDATE accounts SET balance = balance + ? WHERE id = ?;', values: [amount, toId] },
    { statement: 'INSERT INTO ledger (from_id, to_id, amount, at) VALUES (?, ?, ?, ?);', values: [fromId, toId, amount, Date.now()] },
  ] });
}

डेटाबेस को हर ऐप स्टार्ट पर सिर्फ़ एक बार खोलें, भले ही दो स्क्रीन एक साथ माँगें:

const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
let ready = null;

function db(database) {
  if (!ready) ready = (async () => {
    try {
      await DB.createConnection({ database, version: 1, encrypted: false, mode: 'no-encryption', readonly: false });
    } catch (e) {
      if (!/already exists/i.test(e.message)) throw e;   // a page reload keeps the native connection
    }
    if (!(await DB.isDBOpen({ database, readonly: false })).result) await DB.open({ database, readonly: false });
    return database;
  })();
  return ready;
}

ध्यान दें: ऐप SQLCipher के बिना बना है, इसलिए डेटाबेस एन्क्रिप्टेड नहीं होते: encrypted: true, setEncryptionSecret, changeEncryptionSecret, isSecretStored और बाकी एन्क्रिप्शन कॉल "Encryption is not available in this app" के साथ reject होते हैं। isInConfigEncryption() का जवाब false है। बाकी सब (क्वेरी, बाइंड की गई वैल्यू, ट्रांज़ैक्शन, addUpgradeStatement के साथ वर्ज़न वाले अपग्रेड, JSON इम्पोर्ट/एक्सपोर्ट) प्लगइन का अपना कोड है। Rejection में SQLite का त्रुटि टेक्स्ट होता है।

Capacitor.Clipboard Capacitor#

Capacitor.Plugins.Clipboard — write(options), read()

उदाहरण

टेक्स्ट (या लिंक) को सिस्टम क्लिपबोर्ड में कॉपी करता है और वापस पढ़ता है (@capacitor/clipboard 8.0.1).

लौटाता है: write({ string?, url?, image?, label? }) → Promise void। read() → Promise { value, type } (टेक्स्ट के लिए type 'text/plain' होता है)। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

async function copyCode(code) {
  var Clipboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Clipboard;
  if (!Clipboard) { alert('Copy is not available here'); return; }
  await Clipboard.write({ string: code, label: 'Invite code' });
}

async function pasteCode(input) {
  var Clipboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Clipboard;
  if (!Clipboard) return;
  try {
    var r = await Clipboard.read();
    input.value = r.value;
  } catch (e) {
    // An EMPTY clipboard is a rejection: "There is no data on the clipboard".
    if (/no data/i.test(e.message)) input.value = '';
    else alert('Could not read the clipboard: ' + e.message);
  }
}

AI से बने ऐप में Capacitor जैसा रैपर खाली क्लिपबोर्ड को इसमें बदल देता है '':

import { Clipboard } from '@/lib/appmintNative';

await Clipboard.write({ string: 'ABC-123' });
const { value } = await Clipboard.read();   // '' when the clipboard is empty

लिंक कॉपी करें और टैप के फ़ीडबैक से उसकी पुष्टि करें:

async function copyLink(url) {
  var P = window.Capacitor && window.Capacitor.Plugins;
  if (!P || !P.Clipboard) { alert('Copy is not available here'); return; }
  await P.Clipboard.write({ url: url });
  if (P.Haptics) P.Haptics.impact({ style: 'LIGHT' });
  copiedToast.hidden = false;
}

ध्यान दें: write को string, url या image (data URL) में से एक चाहिए, वरना वह "No data provided" के साथ reject होता है। Android 12+ पढ़ने पर अपना "pasted from…" नोटिस दिखाता है - यह OS है, ऐप नहीं। रैपर का write सिर्फ़ भेजता है string || url.

Capacitor.Contacts Capacitor#

Capacitor.Plugins.Contacts — getContacts, getContact, pickContact, createContact, deleteContact

उदाहरण

फ़ोन की एड्रेस बुक, @capacitor-community/contacts API के साथ। @capacitor-community/contacts (template/plugins/contacts) शामिल किया गया है। npm पैकेज के लिए लिखा कोड बिना बदलाव के चलता है।

लौटाता है: checkPermissions() / requestPermissions() → { contacts, contactsWrite } (हर एक 'granted' | 'denied' | 'prompt'; contacts पढ़ने की अनुमति है, contactsWrite जोड़ने और हटाने की); getContacts({ projection }) → { contacts: [ContactPayload] }; getContact({ contactId, projection }) और pickContact({ projection }) → { contact }; createContact({ contact }) → { contactId }; deleteContact({ contactId }) → void। projection फ़ील्ड चुनता है: { name, phones, emails, organization, birthday, note, urls, postalAddresses, image } (हर एक true)। ज़रूरत: पढ़ने के लिए चरण 4 (Access) में Contacts टिक करें, और जोड़ने या हटाने के लिए Edit Contacts भी। HTML, ZIP और AI-Studio बिल्ड ये दोनों अपने आप टिक कर देते हैं जब कोड Contacts.getContacts( / getContact( / pickContact( (पढ़ना) या Contacts.createContact( / deleteContact( (दोनों) कॉल करता है। प्लगइन पहली बार इस्तेमाल पर यूज़र से पूछता है; बॉक्स टिक न हो तो कॉल "Permission is required to access contacts." के साथ reject होता है - और जिस ऐप में Contacts, SMS या Call log में से कुछ भी टिक नहीं है, उसमें प्लगइन होता ही नहीं (Capacitor "not implemented" के साथ reject करता है)। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;

async function friendsWithPhones() {
  if (!Contacts) return [];
  const { contacts } = await Contacts.requestPermissions();
  if (contacts !== 'granted') return [];
  const res = await Contacts.getContacts({ projection: { name: true, phones: true } });
  return res.contacts
    .filter((c) => c.phones && c.phones.length)
    .map((c) => ({ id: c.contactId, name: (c.name && c.name.display) || '', phone: c.phones[0].number }));
}

यूज़र को सिस्टम पिकर से एक व्यक्ति चुनने दें:

const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;

inviteBtn.onclick = async () => {
  if (!Contacts) return;
  try {
    const { contact } = await Contacts.pickContact({ projection: { name: true, phones: true, emails: true } });
    inviteField.value = (contact.emails && contact.emails[0] && contact.emails[0].address) || '';
  } catch (e) {
    // The user closed the picker, or refused access.
  }
};

ऐप से बिज़नेस कार्ड को एड्रेस बुक में सेव करें:

const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;

async function saveCard(card) {
  const perm = await Contacts.requestPermissions();
  if (perm.contactsWrite !== 'granted') return null;
  const { contactId } = await Contacts.createContact({ contact: {
    name: { given: card.first, family: card.last },
    organization: { company: card.company, jobTitle: card.title },
    phones: [{ type: 'work', label: 'work', number: card.phone }],
    emails: [{ type: 'work', label: 'work', address: card.email }],
  } });
  return contactId;
}

ध्यान दें: Android contactId, name, phones, emails, organization, birthday, note, urls, postalAddresses और image तभी भरता है जब प्रोजेक्शन उन्हें माँगे - सिर्फ़ वही माँगें जो आप दिखाते हैं। Google Play पर कॉन्टैक्ट पढ़ना संवेदनशील अनुमति है: लिस्टिंग के डेटा-सेफ़्टी फ़ॉर्म में बताएँ कि क्यों। AI से बने ऐप listContacts(), pickContact() और addContact() इस्तेमाल करते हैं, यहाँ से @/lib/appmintNative.

Capacitor.Device Capacitor#

Capacitor.Plugins.Device

उदाहरण

आधिकारिक Capacitor Device प्लगइन, जो ऐप में शामिल है: फ़ोन का मॉडल, OS वर्ज़न, बैटरी, एक स्थिर ID और भाषा।

लौटाता है: Promise। getInfo() → { model, platform, operatingSystem, osVersion, androidSDKVersion, manufacturer, isVirtual, webViewVersion, … }; getId() → { identifier }; getBatteryInfo() → { batteryLevel (0–1), isCharging }; getLanguageCode() → { value }। ज़रूरत: चालू करने के लिए कुछ नहीं। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

फ़ोन और बैटरी दिखाएँ।

async function showDevice() {
  var cap = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Device;
  if (!cap) { document.getElementById('out').textContent = navigator.userAgent; return; }
  try {
    var info = await cap.getInfo();
    var battery = await cap.getBatteryInfo();
    document.getElementById('out').textContent =
      info.manufacturer + ' ' + info.model + ' - ' + info.operatingSystem + ' ' + info.osVersion +
      ' - battery ' + Math.round(battery.batteryLevel * 100) + '%' + (battery.isCharging ? ' (charging)' : '');
  } catch (err) {
    document.getElementById('out').textContent = 'Could not read device info';
  }
}

एक स्थिर ID और भाषा।

async function helloServer() {
  var cap = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Device;
  if (!cap) return;
  var id = (await cap.getId()).identifier;
  var lang = (await cap.getLanguageCode()).value;     // e.g. "en"
  await fetch('https://api.example.com/hello?lang=' + encodeURIComponent(lang), {
    method: 'POST', body: JSON.stringify({ device: id })
  });
}

AI से बने ऐप में रैपर इस्तेमाल करें, जो वेब पर भी चलता है:

import { Device } from '@/lib/appmintNative';
const info = await Device.getInfo();

ध्यान दें: Android बिल्ड ID, सुरक्षा पैच, स्क्रीन, मेमोरी और नेटवर्क के लिए शेल का WebToApk.getDeviceInfo() ज़्यादा जानकारी देता है। प्लगइन की ids हार्डवेयर ids नहीं हैं; फ़ैक्टरी रीसेट के बाद ये बदल सकती हैं।

Capacitor.Dialog Capacitor#

Capacitor.Plugins.Dialog — alert, confirm, prompt

उदाहरण

असली Android सिस्टम डायलॉग दिखाता है: एक संदेश, हाँ/नहीं सवाल, या एक लाइन का टेक्स्ट सवाल (@capacitor/dialog 8.0.1).

लौटाता है: alert({ title?, message, buttonTitle? }) → Promise void। confirm({ title?, message, okButtonTitle?, cancelButtonTitle? }) → { value: boolean }। prompt({ title?, message, okButtonTitle?, cancelButtonTitle?, inputPlaceholder?, inputText? }) → { value: string, cancelled: boolean }। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Dialog = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Dialog;

async function deleteNote(id) {
  if (!Dialog) return;
  var r = await Dialog.confirm({
    title: 'Delete note?',
    message: 'This cannot be undone.',
    okButtonTitle: 'Delete',
    cancelButtonTitle: 'Keep'
  });
  if (r.value) removeNote(id);
}

Alert और prompt:

async function renameFlow() {
  if (!Dialog) return;
  await Dialog.alert({ title: 'Saved', message: 'Your changes are stored.', buttonTitle: 'OK' });

  var p = await Dialog.prompt({ title: 'Rename', message: 'New name', inputText: 'Groceries', inputPlaceholder: 'List name' });
  if (!p.cancelled && p.value.trim()) renameList(p.value.trim());
}

AI से बने ऐप में रैपर कभी reject नहीं होता: खारिज करना { value: false } / { cancelled: true } है, और वेब पर यह ब्राउज़र के अपने डायलॉग इस्तेमाल करता है:

import { Dialog } from '@/lib/appmintNative';

const { value } = await Dialog.confirm({ title: 'Delete note?', message: 'This cannot be undone.' });
if (value) removeNote(id);

ध्यान दें: message ज़रूरी है - इसके बिना प्लगइन "Please provide a message for the dialog" के साथ reject करता है। डायलॉग मोडल होते हैं; इन्हें सिर्फ़ उन फ़ैसलों के लिए इस्तेमाल करें जिन पर रुकना ज़रूरी है।

Capacitor.Filesystem Capacitor#

Capacitor.Plugins.Filesystem

उदाहरण

स्टॉक Capacitor Filesystem प्लगइन: ऐप के अपने स्टोरेज में फ़ाइलें पढ़ें और लिखें (यूज़र के चुने फ़ोल्डर में नहीं - उसके लिए इस्तेमाल करें WebToApkFS).

लौटाता है: हर तरीका Promise देता है और विफल होने पर reject होता है (जैसे ऐसी फ़ाइल पढ़ना जो मौजूद नहीं)। readFile → { data }, writeFile → { uri }, readdir → { files: [{ name, type, size, mtime, uri }] }, mkdir / deleteFile → कुछ नहीं। ज़रूरत: चालू करने के लिए कुछ नहीं; 'DATA' और 'CACHE' को किसी अनुमति की ज़रूरत नहीं।

पेज में Directory / Encoding इम्पोर्ट नहीं होते, इसलिए सादी स्ट्रिंग दें: 'DATA' (ऐप की निजी फ़ाइलें, अनइंस्टॉल तक रहती हैं) या 'CACHE' (सिस्टम इसे साफ़ कर सकता है), और टेक्स्ट के लिए 'utf8':

async function saveAndReadBack() {
  var Fs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Filesystem;
  if (!Fs) { console.log('Filesystem plugin not available (not inside the app)'); return; }

  try {
    await Fs.mkdir({ path: 'notes', directory: 'DATA', recursive: true });
    await Fs.writeFile({ path: 'notes/today.txt', data: 'Hello', directory: 'DATA', encoding: 'utf8', recursive: true });

    var r = await Fs.readFile({ path: 'notes/today.txt', directory: 'DATA', encoding: 'utf8' });
    console.log('text:', r.data);

    var dir = await Fs.readdir({ path: 'notes', directory: 'DATA' });
    dir.files.forEach(function (f) { console.log(f.type, f.name, f.size); });   // type: 'file' | 'directory'

    await Fs.deleteFile({ path: 'notes/today.txt', directory: 'DATA' });
  } catch (e) {
    console.log('File error:', e.message);   // e.g. the file does not exist
  }
}

बाइनरी डेटा base64 में लिखने या पढ़ने के लिए encoding छोड़ दें:

var Fs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Filesystem;
var base64Data = btoa('raw bytes here');   // any base64 string, e.g. from a canvas or FileReader
if (Fs) {
  Fs.writeFile({ path: 'blobs/data.bin', data: base64Data, directory: 'CACHE', recursive: true })
    .then(function (w) { console.log('written to', w.uri); })
    .catch(function (e) { console.log('write failed:', e.message); });
}

AI से बने ऐप में, इस प्लगइन को इस्तेमाल करने वाला @/lib/appmintNative रैपर fileTransfer है (यह डाउनलोड और अपलोड को इसमें स्टेज करता है 'CACHE'):

import { fileTransfer } from '@/lib/appmintNative';

const r = await fileTransfer.download('https://example.com/report.pdf', 'report.pdf', {
  onProgress: (p) => console.log(Math.round(p.fraction * 100) + '%'),
});
if (r.path) console.log('saved in the app at', r.path);   // on the web the browser saves it instead

ध्यान दें: window.Capacitor सिर्फ़ ऐप के अंदर होता है - हमेशा फ़ीचर-डिटेक्ट करें। 'DATA' में रखी फ़ाइलें ऐप की निजी होती हैं और अनइंस्टॉल पर मिट जाती हैं; फ़ाइलें ऐसी जगह रखनी हों जहाँ यूज़र उन्हें देख सके, तो WebToApkFS (यूज़र का दिया हुआ फ़ोल्डर) या डाउनलोड इस्तेमाल करें।

Capacitor.FileTransfer Capacitor#

Capacitor.Plugins.FileTransfer

उदाहरण

आधिकारिक Capacitor File Transfer प्लगइन: किसी URL को फ़ोन की फ़ाइल में डाउनलोड करता है, या फ़ोन से फ़ाइल अपलोड करता है, नेटिव तरीके से, प्रोग्रेस इवेंट के साथ।

लौटाता है: downloadFile({url, path, headers?, progress?}) → Promise<{path}>; uploadFile({url, path, fileKey?, mimeType?, method?, headers?, progress?}) → Promise<{bytesSent, responseCode, response, headers}>। प्रोग्रेस 'progress' लिसनर इवेंट {type, url, bytes, contentLength, lengthComputable} के रूप में आती है। विफलता {message, code} के साथ reject होती है। ज़रूरत: चालू करने के लिए कुछ नहीं। window.Capacitor सिर्फ़ उन पेजों में होता है जिन्हें ऐप खुद चलाता है - हमेशा फ़ीचर-डिटेक्ट करें।

प्रोग्रेस के साथ ऐप के कैश में डाउनलोड करें:

async function download(url, name, onPct) {
  const P = window.Capacitor && window.Capacitor.Plugins;
  if (!P || !P.FileTransfer || !P.Filesystem) return null;          // not in the app
  const target = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
  const listener = await P.FileTransfer.addListener('progress', function (p) {
    if (p.url === url && p.lengthComputable) onPct(Math.round(p.bytes / p.contentLength * 100));
  });
  try {
    const r = await P.FileTransfer.downloadFile({ url: url, path: target.uri, progress: true });
    return r.path;
  } catch (e) {
    alert('Download failed: ' + e.message);
    return null;
  } finally {
    listener.remove();
  }
}

ऐसी फ़ाइल अपलोड करें जो फ़ोन पर पहले से है:

const P = window.Capacitor && window.Capacitor.Plugins;
if (P && P.FileTransfer) {
  P.FileTransfer.uploadFile({
    url: 'https://example.com/api/upload', path: localFileUri,
    fileKey: 'file', mimeType: 'image/jpeg', headers: { Authorization: 'Bearer ' + token }
  }).then(function (r) { console.log('server said', r.responseCode, r.response); })
    .catch(function (e) { alert('Upload failed: ' + e.message); });
}

विफल ट्रांसफ़र को उसके कोड से बताएँ:

async function safeDownload(url, target) {
  const P = window.Capacitor && window.Capacitor.Plugins;
  if (!P || !P.FileTransfer) { alert('Downloads need the app'); return null; }
  try {
    const r = await P.FileTransfer.downloadFile({ url: url, path: target });
    return r.path;
  } catch (e) {
    console.log('transfer failed', e.code, e.message);
    alert('Could not download the file.');
    return null;
  }
}

ध्यान दें: पाथ फ़ाइल पाथ या file:// URI होना चाहिए, Blob नहीं - Blob को पहले Filesystem.writeFile से कैश में लिखें। Android 10 और पुराने पर पब्लिक स्टोरेज का पाथ स्टोरेज अनुमति माँगता है। AI से बने ऐप में @/lib/appmintNative से fileTransfer को प्राथमिकता दें, जो यह सब करता है और वेब पर भी चलता है।

Capacitor.FileViewer Capacitor#

Capacitor.Plugins.FileViewer

उदाहरण

आधिकारिक Capacitor File Viewer प्लगइन: किसी दस्तावेज़ या मीडिया फ़ाइल को फ़ोन के व्यूअर ऐप में खोलता है, वेब पते से, लोकल फ़ाइल पाथ से, या ऐप में बंडल की गई फ़ाइल से।

लौटाता है: हर तरीका एक Promise<void> देता है जो कुछ भी फ़ाइल न खोल पाए तो {message, code} के साथ reject होता है। ज़रूरत: चालू करने के लिए कुछ नहीं। window.Capacitor सिर्फ़ उन पेजों में होता है जिन्हें ऐप खुद चलाता है - हमेशा फ़ीचर-डिटेक्ट करें।

async function openPdf(url) {
  const FV = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.FileViewer;
  if (!FV) { window.open(url, '_blank'); return; }          // a normal browser: open a tab
  try {
    await FV.openDocumentFromUrl({ url: url });
  } catch (e) {
    alert('No app on this phone can open this file.');
  }
}

फ़ोन पर मौजूद एक फ़ाइल, जैसे वह जो इससे लिखी गई हो Capacitor.Plugins.Filesystem:

async function openSaved(name) {
  const P = window.Capacitor && window.Capacitor.Plugins;
  if (!P || !P.FileViewer || !P.Filesystem) return;
  const f = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
  try {
    await P.FileViewer.openDocumentFromLocalPath({ path: f.uri.replace(/^file:\/\//, '') });
  } catch (e) {
    alert('Cannot open ' + name + ': ' + e.message);
  }
}

openDocumentFromResources({path}) APK के अपने assets फ़ोल्डर में रखी फ़ाइल खोलता है। यही तीनों तरीके वीडियो और ऑडियो के लिए previewMediaContentFromUrl, previewMediaContentFromLocalPath और previewMediaContentFromResources के रूप में भी मौजूद हैं।

फ़ाइल डाउनलोड करें और आते ही उसे खोलें:

async function downloadAndOpen(url, name) {
  const P = window.Capacitor && window.Capacitor.Plugins;
  if (!P || !P.FileTransfer || !P.Filesystem || !P.FileViewer) return;
  const f = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
  const r = await P.FileTransfer.downloadFile({ url: url, path: f.uri });
  await P.FileViewer.openDocumentFromLocalPath({ path: r.path.replace(/^file:\/\//, '') });
}

ध्यान दें: AI से बने ऐप में @/lib/appmintNative से fileViewer.open(target) को प्राथमिकता दें, जो सही तरीका चुनता है और वेब पर भी चलता है। लोकल पाथ सादा पाथ होता है (बिना file://).

Capacitor.Geolocation Capacitor#

Capacitor.Plugins.Geolocation

उदाहरण

आधिकारिक Capacitor Geolocation प्लगइन, जो ऐप में शामिल है: फ़ोन की लोकेशन एक बार, या लगातार अपडेट।

लौटाता है: Promise। getCurrentPosition(opts) → { timestamp, coords: { latitude, longitude, accuracy, altitude, speed, heading, … } }; watchPosition(opts, callback) → वॉच id (स्ट्रिंग); clearWatch({ id }); checkPermissions() / requestPermissions() → { location, coarseLocation } ('granted' | 'denied' | 'prompt' | …)। ज़रूरत: चरण 4 (Access) में GPS और/या Location - HTML, ZIP और AI से बने ऐप के लिए, जब आपकी फ़ाइलें getCurrentPosition या watchPosition कॉल करती हैं तो बिल्ड इन्हें अपने आप भी चालू कर देता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

एक बार लोकेशन लें, पहले पूछकर।

async function whereAmI() {
  var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
  if (!geo) { showMessage('Open the app to use location.'); return; }
  try {
    var perm = await geo.checkPermissions();
    if (perm.location !== 'granted' && perm.coarseLocation !== 'granted') {
      perm = await geo.requestPermissions();
      if (perm.location !== 'granted' && perm.coarseLocation !== 'granted') {
        showMessage('Location is off for this app.');
        return;
      }
    }
    var pos = await geo.getCurrentPosition({ enableHighAccuracy: true, timeout: 15000 });
    showMessage(pos.coords.latitude.toFixed(5) + ', ' + pos.coords.longitude.toFixed(5));
  } catch (err) {
    showMessage('No location: ' + err.message);   // location off in settings, timeout, …
  }
}

लगातार अपडेट। कॉलबैक को मिलता है (position, error).

var watchId = null;

async function startTracking() {
  var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
  if (!geo) return;
  watchId = await geo.watchPosition({ enableHighAccuracy: true }, function (pos, err) {
    if (err || !pos) return;
    addPointToMap(pos.coords.latitude, pos.coords.longitude);
  });
}

async function stopTracking() {
  var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
  if (geo && watchId) { await geo.clearWatch({ id: watchId }); watchId = null; }
}

AI से बने ऐप में रैपर इस्तेमाल करें, जो वेब पर भी चलता है:

import { Geolocation } from '@/lib/appmintNative';
const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });

ध्यान दें: सादा navigator.geolocation ऐप में भी चलता है। बिल्ड के समय लोकेशन स्विच बंद थे तो अनुमति बिना पूछे मना हो जाती है। Android 12+ पर यूज़र सिर्फ़ अंदाज़न लोकेशन की अनुमति दे सकता है (coarseLocation दी गई)। लोकेशन निजी डेटा है: इसे अपने Play Data safety फ़ॉर्म में बताएँ।

Capacitor.Haptics Capacitor#

Capacitor.Plugins.Haptics

उदाहरण

आधिकारिक Capacitor Haptics प्लगइन (@capacitor/haptics), जो ऐप में शामिल है: हल्का/मध्यम/भारी टैप, सफलता/चेतावनी/त्रुटि फ़ीडबैक, सिलेक्शन टिक और सादा वाइब्रेशन।

लौटाता है: हर तरीका ऐसा Promise देता है जो बिना कुछ दिए resolve होता है। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप वाइब्रेशन अनुमति घोषित करता है, चाहे चरण 4 (Access) में Vibrate टिक हो या नहीं। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

function haptics() {
  return window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.Haptics : null;
}

async function tap(style) {            // 'LIGHT' | 'MEDIUM' | 'HEAVY'
  var h = haptics();
  if (!h) return;
  try { await h.impact({ style: style }); } catch (e) { console.log('haptics failed', e); }
}

async function result(type) {          // 'SUCCESS' | 'WARNING' | 'ERROR'
  var h = haptics();
  if (h) { try { await h.notification({ type: type }); } catch (e) {} }
}

document.getElementById('add').addEventListener('click', function () { tap('LIGHT'); });
document.getElementById('pay').addEventListener('click', function () { result('SUCCESS'); });

पिकर या स्लाइडर के लिए सिलेक्शन टिक, और सादा वाइब्रेशन:

var h = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.Haptics : null;
var wheel = document.getElementById('wheel');

wheel.addEventListener('pointerdown', function () { if (h) h.selectionStart(); });
wheel.addEventListener('change', function () { if (h) h.selectionChanged(); });
wheel.addEventListener('pointerup', function () { if (h) h.selectionEnd(); });

document.getElementById('buzz').addEventListener('click', function () {
  if (h) h.vibrate({ duration: 300 });   // milliseconds
});

त्रुटि पर वाइब्रेट करें और साथ में दिखने वाला संदेश भी दें:

var h = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Haptics;

function rejectInput(field) {
  field.classList.add('invalid');
  if (h) h.notification({ type: 'ERROR' }).catch(function () {});
}

ध्यान दें: स्ट्रिंग बड़े अक्षरों में होती हैं ('HEAVY', 'heavy' नहीं)। AI से बने ऐप में import { Haptics } from '@/lib/appmintNative' वही नाम देता है। हर बीट की अलग तेज़ी वाली अपनी लय के लिए इस्तेमाल करें Capacitor.Plugins.AppwrightHaptics.

Capacitor.InAppReview Capacitor#

Capacitor.Plugins.InAppReview — requestReview()

उदाहरण

Google Play से ऐप के अंदर उसकी अपनी "इस ऐप को रेट करें" शीट दिखाने को कहता है। शामिल किया गया @capacitor-community/in-app-review (template/plugins/in-app-review).

लौटाता है: Promise void - यह तब resolve होता है जब Play का फ़्लो ख़त्म हो, और Play कभी नहीं बताता कि शीट दिखी या यूज़र ने क्या किया। Play फ़्लो शुरू न कर पाए तो यह reject होता है। ज़रूरत: चालू करने के लिए कुछ नहीं; शीट दिखने के लिए ऐप Google Play से इंस्टॉल होना चाहिए। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Review = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.InAppReview;

async function afterThirdOrder() {
  if (!Review) return;
  try {
    await Review.requestReview();
  } catch (e) {
    console.log('review flow not available:', e.message);
  }
  // continue the app flow either way — you cannot know if the user rated
}

AI से बने ऐप में:

import { requestReview } from '@/lib/appmintNative';

// after a success moment, not on launch
const asked = await requestReview();   // false where nothing could be asked (web)

सफलता के किसी पल के बाद एक बार पूछें, और याद रखें कि आपने पूछ लिया:

var Review = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.InAppReview;

async function maybeAskForReview() {
  if (!Review || localStorage.getItem('review_asked')) return;
  localStorage.setItem('review_asked', '1');
  try { await Review.requestReview(); } catch (e) { console.log('review not shown:', e.message); }
}

ध्यान दें: Play तय करता है कि शीट कितनी बार दिखे और हर कॉल पर नहीं दिखाता - इससे कभी कोई इनाम न जोड़ें और "हमें रेट करें" बटन से इसके खुलने की उम्मीद में कभी न पूछें (उसके लिए स्टोर लिस्टिंग खोलें)। सफलता के पल के बाद पूछें, स्टार्टअप पर नहीं। साइडलोड या डीबग इंस्टॉल पर आमतौर पर कुछ नहीं दिखता।

Capacitor.KeepAwake Capacitor#

Capacitor.Plugins.KeepAwake — keepAwake(), allowSleep(), isKeptAwake(), isSupported()

उदाहरण

स्क्रीन को मंद होने और लॉक होने से रोकता है जब कुछ दिखता रहना ज़रूरी हो - रेसिपी, रूट, QR कोड, टाइमर। शामिल किया गया @capacitor-community/keep-awake (template/plugins/keep-awake).

लौटाता है: keepAwake() / allowSleep() → Promise void। isKeptAwake() → { isKeptAwake: boolean }। isSupported() → { isSupported: true }। ज़रूरत: कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है; कोई अनुमति नहीं। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var KA = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.KeepAwake;

async function startCooking() {
  if (KA) await KA.keepAwake();
  showSteps();
}

async function stopCooking() {
  if (KA) await KA.allowSleep();      // always release when the view closes
}

if (KA) KA.isKeptAwake().then(function (r) { console.log('awake?', r.isKeptAwake); });

AI से बने ऐप में (वेब पर Screen Wake Lock API):

import { keepAwake } from '@/lib/appmintNative';

useEffect(() => {
  void keepAwake(true);
  return () => { void keepAwake(false); };
}, []);

स्क्रीन को सिर्फ़ तब चालू रखें जब टाइमर चल रहा हो:

var KA = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.KeepAwake;

async function runTimer(seconds) {
  if (KA) await KA.keepAwake();
  await new Promise(function (done) { setTimeout(done, seconds * 1000); });
  if (KA) await KA.allowSleep();
  alert('Time is up');
}

ध्यान दें: यह फ़्लैग ऐप विंडो का है: यह तभी काम करता है जब ऐप सामने हो, और allowSleep() तक चालू रहता है - स्क्रीन से निकलने के हर रास्ते पर इसे छोड़ें। जब कुछ भी स्क्रीन को चालू न रख पाए तो keepAwake() false लौटाता है।

Capacitor.Keyboard Capacitor#

Capacitor.Plugins.Keyboard — show(), hide(), addListener('keyboardDidShow' | ...)

उदाहरण

सॉफ़्टवेयर कीबोर्ड खोलता या बंद करता है और पेज को बताता है कि वह कब दिखा और कितना ऊँचा है (@capacitor/keyboard 8.0.5).

लौटाता है: show() / hide() → Promise void। addListener(event, fn) → remove() वाले हैंडल का Promise; दिखाने वाले इवेंट { keyboardHeight } CSS पिक्सेल में देते हैं। इवेंट: keyboardWillShow, keyboardDidShow, keyboardWillHide, keyboardDidHide। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;

if (Keyboard) {
  Keyboard.addListener('keyboardDidShow', function (info) {
    console.log('keyboard height', info.keyboardHeight);
    document.body.classList.add('typing');       // e.g. hide the bottom tab bar
  });
  Keyboard.addListener('keyboardDidHide', function () {
    document.body.classList.remove('typing');
  });
}

function onSend() {
  if (Keyboard) Keyboard.hide().catch(function () {});   // rejects if no field is focused
}

AI से बने ऐप में लेआउट के लिए onKeyboard() इस्तेमाल करें - यह कीबोर्ड का सिर्फ़ वह हिस्सा बताता है जिसे आकार बदला हुआ पेज पहले से नहीं हटा चुका - और उसे बंद करने के लिए hideKeyboard():

import { onKeyboard, hideKeyboard, Keyboard } from '@/lib/appmintNative';

const off = onKeyboard((px) => { composer.style.paddingBottom = `${px}px`; });  // call off() on unmount
hideKeyboard();

const h = Keyboard.addListener('keyboardWillShow', ({ keyboardHeight }) => console.log(keyboardHeight));
h.remove();

बटन टैप के बाद किसी फ़ील्ड के लिए कीबोर्ड दिखाएँ:

var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;

searchBtn.addEventListener('click', function () {
  searchInput.focus();
  if (Keyboard) Keyboard.show().catch(function () {});
});

ध्यान दें: शेल कीबोर्ड के लिए पेज का आकार पहले से बदलता है, इसलिए पूरा keyboardHeight पैडिंग के रूप में न जोड़ें - नीचे का बार पहले से कीज़ के ऊपर होता है। setAccessoryBarVisible, setStyle, setResizeMode और setScroll Android पर लागू नहीं हैं - इन्हें कॉल न करें। किसी पर फ़ोकस न होने पर hide() "Can't close keyboard, not currently focused" के साथ reject होता है।

Capacitor.LocalNotifications Capacitor#

Capacitor.Plugins.LocalNotifications — schedule, cancel, getPending, requestPermissions, events

उदाहरण

ऐसे नोटिफ़िकेशन जो ऐप खुद पोस्ट करता है - अभी, या किसी समय पर - आधिकारिक @capacitor/local-notifications API (com.capacitorjs:local-notifications) के साथ। npm पैकेज के लिए लिखा कोड बिना बदलाव के चलता है।

लौटाता है: requestPermissions() / checkPermissions() → { display: 'granted' | 'denied' | 'prompt' }; schedule({ notifications: [{ id, title, body, schedule?: { at | on | every }, extra?, actionTypeId?, channelId? }] }) → { notifications: [{ id }] }; getPending() → { notifications }; cancel({ notifications: [{ id }] }); registerActionTypes({ types }); createChannel / listChannels / deleteChannel; checkExactNotificationSetting() → { exact_alarm }। इवेंट: localNotificationReceived, localNotificationActionPerformed (नोटिफ़िकेशन पर ही टैप के लिए actionId 'tap' होता है)। ज़रूरत: चरण 4 (Access) में Notifications टिक करें - इसके बिना प्लगइन ऐप में होता ही नहीं और हर कॉल "not implemented" के साथ reject होता है। समय वाले नोटिफ़िकेशन के लिए ⏰ Reminders भी टिक करें (सटीक समय और रीबूट के बाद भी बने रहना)। जब कोड @capacitor/local-notifications इम्पोर्ट करता है और LocalNotifications.schedule( कॉल करता है तो HTML, ZIP और AI-Studio बिल्ड दोनों अपने आप टिक कर देते हैं। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;

async function remindIn(minutes, text) {
  if (!LN) return false;
  const { display } = await LN.requestPermissions();
  if (display !== 'granted') return false;
  await LN.schedule({ notifications: [{
    id: Date.now() % 2147483647,
    title: 'Reminder',
    body: text,
    schedule: { at: new Date(Date.now() + minutes * 60000), allowWhileIdle: true },
    extra: { screen: 'tasks' },
  }] });
  return true;
}

यूज़र के नोटिफ़िकेशन पर टैप करने पर सही स्क्रीन खोलें - तब भी जब टैप से ऐप शुरू हुआ हो, क्योंकि इवेंट लिसनर का इंतज़ार करता है:

const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;

if (LN) {
  LN.addListener('localNotificationActionPerformed', ({ actionId, notification }) => {
    if (actionId === 'tap' && notification.extra && notification.extra.screen) {
      location.hash = '#/' + notification.extra.screen;
    }
  });
}

Done / Snooze बटन वाला रोज़ का आदत रिमाइंडर:

const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;

async function dailyWaterReminder() {
  await LN.registerActionTypes({ types: [{ id: 'water', actions: [
    { id: 'done', title: 'Done' },
    { id: 'snooze', title: 'In 30 min' },
  ] }] });
  await LN.schedule({ notifications: [{
    id: 42, title: 'Drink water', body: 'Time for a glass of water.',
    actionTypeId: 'water', schedule: { on: { hour: 10, minute: 0 }, repeats: true },
  }] });
  LN.addListener('localNotificationActionPerformed', ({ actionId }) => {
    if (actionId === 'snooze') {
      LN.schedule({ notifications: [{ id: 43, title: 'Drink water', body: 'Snoozed reminder.',
        schedule: { at: new Date(Date.now() + 30 * 60000) } }] });
    }
  });
}

ध्यान दें: Android 12+ पर समय वाले नोटिफ़िकेशन को exact-alarm की अनुमति चाहिए: पहला schedule() सिस्टम का "Alarms & reminders" पेज खोल सकता है; यूज़र उसे बंद छोड़ दे तब भी नोटिफ़िकेशन आता है, थोड़ी देर से (नतीजे में warning होता है)। प्लगइन के नोटिफ़िकेशन अपना "Default" चैनल इस्तेमाल करते हैं, जो ऐप के बाकी नोटिफ़िकेशन से अलग है। वेब फ़ाइलों से sound सपोर्ट नहीं है (Android चैनल की डिफ़ॉल्ट आवाज़ बजाता है)। ऐप में PIN हो तो टैप अनलॉक स्क्रीन से होकर पेज तक पहुँचते हैं। AI से बने ऐप @/lib/appmintNative से notify() / LocalNotifications.schedule इस्तेमाल करते हैं, जो ऐप के अपने नोटिफ़िकेशन स्टैक से पोस्ट करता है।

Capacitor.Network Capacitor#

Capacitor.Plugins.Network — getStatus(), addListener('networkStatusChange')

उदाहरण

पेज को बताता है कि फ़ोन ऑनलाइन है या नहीं और किस तरह के कनेक्शन पर, और यह कब बदलता है (@capacitor/network 8.0.1).

लौटाता है: getStatus() → Promise { connected: boolean, connectionType: 'wifi' | 'cellular' | 'none' | 'unknown' }। networkStatusChange इवेंट भी यही रूप देता है। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Network = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Network;

function showBanner(s) {
  document.getElementById('offline').hidden = s.connected;
}

if (Network) {
  Network.getStatus().then(showBanner);
  Network.addListener('networkStatusChange', function (s) {
    showBanner(s);
    if (s.connected) retryQueuedWrites();
    if (s.connectionType === 'cellular') console.log('on mobile data');
  });
}

AI से बने ऐप में:

import { Network, networkStatus, onNetworkChange } from '@/lib/appmintNative';

const { connected, connectionType } = await Network.getStatus();
const now = networkStatus();                        // sync: { connected, type }
const off = onNetworkChange((s) => setOnline(s.connected));   // call off() on unmount

मोबाइल डेटा पर बड़ा अपलोड रोकें:

var Network = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Network;

async function canUploadVideo() {
  if (!Network) return navigator.onLine;
  var s = await Network.getStatus();
  if (!s.connected) return false;
  return s.connectionType === 'wifi' || confirm('Upload over mobile data?');
}

ध्यान दें: connected का मतलब है कि फ़ोन के पास नेटवर्क है, यह नहीं कि आपका सर्वर जवाब देता है - फिर भी विफल रिक्वेस्ट संभालें। रैपर के Network.getStatus() और networkStatus() प्लगइन की जगह navigator.onLine / navigator.connection पढ़ते हैं, इसलिए उनका टाइप 'unknown' या '4g' जैसी स्पीड क्लास हो सकता है; onNetworkChange() ऐप में प्लगइन का इवेंट इस्तेमाल करता है।

Capacitor.Preferences Capacitor#

Capacitor.Plugins.Preferences — get / set / remove / keys / clear

उदाहरण

एक छोटा नेटिव की-वैल्यू स्टोर (Android SharedPreferences) स्ट्रिंग के लिए (@capacitor/preferences 8.0.1).

लौटाता है: set({ key, value }), remove({ key }), clear() → Promise void; get({ key }) → { value } (कुंजी न होने पर null); keys() → { keys: string[] }। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Prefs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Preferences;

async function saveTheme(name) {
  if (!Prefs) return false;          // not inside the app
  await Prefs.set({ key: 'theme', value: name });
  return true;
}

async function loadTheme() {
  if (!Prefs) return null;
  var r = await Prefs.get({ key: 'theme' });
  return r.value;            // null if never saved
}

ऑब्जेक्ट को पहले स्ट्रिंग में बदलना होगा:

async function saveUser() {
  if (!Prefs) return;
  await Prefs.set({ key: 'user', value: JSON.stringify({ id: 7, name: 'Asha' }) });
  var u = JSON.parse((await Prefs.get({ key: 'user' })).value || 'null');
  var all = (await Prefs.keys()).keys;
  await Prefs.remove({ key: 'user' });
}

सेटिंग्स स्क्रीन से सेव की गई कुंजियों की सूची देखें और उन्हें हटाएँ:

async function resetSettings() {
  if (!Prefs) return;
  var k = (await Prefs.keys()).keys;
  console.log('clearing', k.length, 'saved values');
  await Prefs.clear();
}

ध्यान दें: @/lib/appmintNative में जानबूझकर कोई Preferences रैपर नहीं है: localStorage ऐप में पहले से असली और स्थायी है, और दूसरा स्टोर एक ऐप का डेटा दो जगह बाँट देगा। AI से बने ऐप को localStorage (या डेटा रनटाइम) ही इस्तेमाल करना चाहिए। हाथ से लिखे पेज में Preferences तभी इस्तेमाल करें जब आप अपनी सारी सेटिंग्स वहीं रखना चाहें, और हर वैल्यू के लिए एक ही स्टोर चुनें। configure({ group }) स्टोर का नाम बदलता है (डिफ़ॉल्ट CapacitorStorage).

Capacitor.PrivacyScreen Capacitor#

Capacitor.Plugins.PrivacyScreen — enable(), disable(), isEnabled()

उदाहरण

आधिकारिक @capacitor/privacy-screen प्लगइन: स्क्रीनशॉट और स्क्रीन रिकॉर्डिंग रोकता है और हाल के ऐप वाले व्यू में ऐप की सामग्री छिपाता है। इसे पहले से शामिल किया गया है ताकि इसे कॉल करने वाले इम्पोर्ट किए गए Capacitor प्रोजेक्ट काम करें।

लौटाता है: enable({android}) → {success}; disable() → {success}; isEnabled() → {enabled}। ज़रूरत: चालू करने के लिए कुछ नहीं।

const Privacy = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PrivacyScreen;

async function openVault() {
  if (Privacy) await Privacy.enable({ android: { privacyModeOnActivityHidden: 'dim' } });
  showVault();
}
async function closeVault() {
  if (Privacy) await Privacy.disable();
}

टॉगल करने से पहले मौजूदा स्थिति जाँचें:

async function toggleProtection() {
  if (!Privacy) return;
  var s = await Privacy.isEnabled();
  if (s.enabled) await Privacy.disable();
  else await Privacy.enable();
}

स्क्रीन को सिर्फ़ तब सुरक्षित रखें जब कोई संवेदनशील व्यू खुला हो:

async function showCardNumber() {
  if (Privacy) await Privacy.enable({ android: { privacyModeOnActivityHidden: 'splash' } });
  cardBox.hidden = false;
}
async function hideCardNumber() {
  cardBox.hidden = true;
  if (Privacy) await Privacy.disable();
}

ध्यान दें: privacyModeOnActivityHidden: 'none', 'dim' या 'splash'। ऐप के लिए लिखा कोड @/lib/appmintNative से WebToApk.setSecureScreen(true) / privacyScreen.enable() इस्तेमाल करे, जो पेज के साथ चलता है (ऐप के पेज छोड़ने पर छूट जाता है); दोनों मिलाने पर आख़िरी कॉल जीतता है।

Capacitor.PushNotifications Capacitor#

Capacitor.Plugins.PushNotifications — register, requestPermissions, registration, pushNotificationReceived

उदाहरण

आपके अपने सर्वर से आपके Firebase प्रोजेक्ट के ज़रिए पुश नोटिफ़िकेशन, आधिकारिक @capacitor/push-notifications API (com.capacitorjs:push-notifications, शेल के PushNotificationsPlugin.kt से रजिस्टर) के साथ। npm पैकेज के लिए लिखा कोड बिना बदलाव के चलता है: register(), फिर registration इवेंट से मिले टोकन पर Firebase Admin SDK या FCM HTTP v1 API से भेजें।

लौटाता है: requestPermissions() / checkPermissions() → { receive: 'granted' | 'denied' | 'prompt' }; register() / unregister() → void (टोकन registration इवेंट { value } के रूप में आता है, विफलता registrationError { error } के रूप में); getDeliveredNotifications() → { notifications }; removeDeliveredNotifications({ notifications }), removeAllDeliveredNotifications(); createChannel({ id, name, importance? }), listChannels(), deleteChannel({ id })। इवेंट: pushNotificationReceived (ऐप खुला होने पर मैसेज: { id, title?, body?, data }) और pushNotificationActionPerformed ({ actionId: 'tap', notification: { id, data } })। ज़रूरत: AppMint Push चालू करके बिल्ड करें और अपनी google-services.json अपलोड करें (Notifications चरण) - टोकन उसी Firebase प्रोजेक्ट का होता है। इसके बिना register() कोड PUSH_NOT_CONFIGURED ("Push is not set up in this app") के साथ reject होता है। जब कोड PushNotifications.register( / requestPermissions( / addListener( कॉल करता है तो HTML, ZIP और AI-Studio बिल्ड Notifications अपने आप टिक कर देते हैं। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;

async function enablePush(userId) {
  if (!Push) return;
  await Push.addListener('registration', ({ value }) => {
    // Your server stores the token and sends to it later.
    fetch('https://api.example.com/push-tokens', {
      method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ userId, token: value, platform: 'android' }),
    });
  });
  await Push.addListener('registrationError', ({ error }) => console.warn('push:', error));
  const { receive } = await Push.requestPermissions();
  if (receive !== 'granted') return;
  try { await Push.register(); }
  catch (e) { if (e.code === 'PUSH_NOT_CONFIGURED') alert('Push is not set up in this build.'); }
}

ऐप खुला होने पर आए मैसेज पर, और ऐप बंद होने पर आए मैसेज के टैप पर प्रतिक्रिया दें (टैप इवेंट आपके लिसनर का इंतज़ार करता है, इसलिए कोल्ड स्टार्ट में भी यह छूटता नहीं):

const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;

if (Push) {
  Push.addListener('pushNotificationReceived', (msg) => {
    alert((msg.title || 'New message') + (msg.body ? ': ' + msg.body : ''));
  });
  Push.addListener('pushNotificationActionPerformed', ({ notification }) => {
    const orderId = notification.data && notification.data.orderId;
    if (orderId) location.hash = '#/orders/' + orderId;
  });
}

ज़रूरी अलर्ट के लिए एक चैनल (Android 8+), जिसका नाम लेने वाले मैसेज इसे इस्तेमाल करते हैं android.notification.channel_id:

const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;

async function setupChannels() {
  if (!Push) return;
  await Push.createChannel({ id: 'orders', name: 'Order updates', description: 'Your order status', importance: 4, vibration: true });
}

ध्यान दें: notification ब्लॉक के साथ भेजा गया मैसेज ऐप के बैकग्राउंड में होने पर Android खुद दिखाता है; उस पर टैप करने से ऐप खुलता है (ऐप में PIN हो तो अनलॉक स्क्रीन से होकर) और pushNotificationActionPerformed चलता है। ऐप खुला हो तो मैसेज pushNotificationReceived के रूप में आते हैं और ट्रे में नहीं दिखते। सिर्फ़-डेटा वाले मैसेज पेज तक तभी पहुँचते हैं जब वह खुला हो। AppMint Push के मैसेज साथ-साथ काम करते रहते हैं - वे इस प्लगइन तक कभी नहीं पहुँचते। AppMint Push की जगह OneSignal से बने ऐप में मैसेज OneSignal पहुँचाता है और इस प्लगइन तक नहीं आते। AI से बने ऐप क्रिएटर के पुश pushInbox() से पाते हैं, यहाँ से @/lib/appmintNative.

Capacitor.ScreenBrightness Capacitor#

Capacitor.Plugins.ScreenBrightness — getBrightness(), setBrightness({ brightness })

उदाहरण

ऐप विंडो की स्क्रीन ब्राइटनेस तय करता है - बोर्डिंग पास या QR कोड के लिए पूरी ब्राइटनेस, फिर वापस। शामिल किया गया @capacitor-community/screen-brightness (template/plugins/screen-brightness).

लौटाता है: getBrightness() → Promise { brightness } (0-1, या -1 जब ऐप ने इसे बदला न हो और स्क्रीन सिस्टम के हिसाब से चल रही हो)। setBrightness({ brightness }) → Promise void। ज़रूरत: कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है; कोई अनुमति नहीं (यह सिर्फ़ इस ऐप की विंडो बदलता है, सिस्टम सेटिंग नहीं)। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var SB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenBrightness;

async function showTicket() {
  if (SB) await SB.setBrightness({ brightness: 1 });     // full brightness
  document.getElementById('qr').hidden = false;
}

async function hideTicket() {
  if (SB) await SB.setBrightness({ brightness: -1 });    // -1 = follow the system again
  document.getElementById('qr').hidden = true;
}

AI से बने ऐप में:

import { brightness } from '@/lib/appmintNative';

await brightness.set(1);        // clamped to 0–1; false where not available (web)
// ... on leaving the screen
await brightness.restore();
const level = await brightness.get();   // -1 = following the system / not available

पहले मौजूदा स्तर पढ़ें और बाद में ठीक वही वापस रखें:

var SB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenBrightness;
var before = -1;

async function boost() {
  if (!SB) return;
  before = (await SB.getBrightness()).brightness;
  await SB.setBrightness({ brightness: 1 });
}
async function undo() {
  if (SB) await SB.setBrightness({ brightness: before });
}

ध्यान दें: हमेशा एक संख्या दें - setBrightness({}) में लागू करने के लिए कोई वैल्यू नहीं है। व्यू बंद होने पर -1 से पहले जैसा करें; ऐप बंद होने पर भी ओवरराइड ख़त्म हो जाता है। वेब पेज बैकलाइट नहीं चला सकता, इसलिए ब्राउज़र में can('brightness') का जवाब 'none' है।

Capacitor.ScreenOrientation Capacitor#

Capacitor.Plugins.ScreenOrientation — orientation(), lock({ orientation }), unlock()

उदाहरण

स्क्रीन ओरिएंटेशन पढ़ता है, एक व्यू के लिए उसे लॉक करता है (गेम, चार्ट, सिग्नेचर पैड) और फिर छोड़ देता है (@capacitor/screen-orientation 8.0.1).

लौटाता है: orientation() → Promise { type } (जैसे 'portrait-primary')। lock() / unlock() → Promise void। इवेंट screenOrientationChange { type } देता है। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

orientation मान: 'portrait', 'landscape', 'portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary', 'natural', 'any'.

var SO = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenOrientation;

async function openChart() {
  if (SO) await SO.lock({ orientation: 'landscape' });
  showChart();
}

async function closeChart() {
  if (SO) await SO.unlock();          // always release when leaving the view
  hideChart();
}

if (SO) {
  SO.orientation().then(function (o) { console.log('now', o.type); });
  SO.addListener('screenOrientationChange', function (o) { console.log('rotated to', o.type); });
}

AI से बने ऐप में:

import { lockOrientation, ScreenOrientation } from '@/lib/appmintNative';

const ok = await lockOrientation('landscape');   // false when refused (always on desktop)
await lockOrientation('any');                    // release

await ScreenOrientation.lock({ orientation: 'portrait' });
await ScreenOrientation.unlock();

लॉक मना होने पर उसे संभालें और यूज़र को बताएँ:

var SO = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenOrientation;
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;

async function tryLandscape() {
  if (!SO) { document.getElementById('rotate-hint').hidden = false; return; }   // ask the user to rotate by hand
  try {
    await SO.lock({ orientation: 'landscape' });
  } catch (e) {
    if (Toast) Toast.show({ text: 'Could not rotate the screen', duration: 'short' });
  }
}

ध्यान दें: रैपर सिर्फ़ portrait / landscape / any जानते हैं: ScreenOrientation.lock({ orientation: 'landscape-secondary' }) सादे landscape पर लॉक करता है। लॉक किए गए व्यू से निकलने का रास्ता यूज़र को दें।

Capacitor.ScreenReader Capacitor#

Capacitor.Plugins.ScreenReader — isEnabled(), speak({ value, language }), addListener('stateChange')

उदाहरण

पेज को बताता है कि TalkBack चालू है या नहीं, और घोषणा बोलता है (@capacitor/screen-reader 8.0.1).

लौटाता है: isEnabled() → Promise { value: boolean }। speak() → Promise void। TalkBack चालू या बंद होने पर stateChange इवेंट { value: boolean } देता है। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var SR = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenReader;

function setCalmMode(on) {
  document.documentElement.classList.toggle('no-motion', on);   // shorten animations
}

if (SR) {
  SR.isEnabled().then(function (r) { setCalmMode(r.value); });
  SR.addListener('stateChange', function (s) { setCalmMode(s.value); });
}

async function announceSaved() {
  if (SR) await SR.speak({ value: 'Order placed', language: 'en' });
}

AI से बने ऐप में (वेब पर speak टेक्स्ट-टू-स्पीच इस्तेमाल करता है; वहाँ isEnabled() false है):

import { screenReader } from '@/lib/appmintNative';

const on = await screenReader.isEnabled();
const off = screenReader.onChange((enabled) => setCalmMode(enabled));
await screenReader.speak('Order placed', 'en');

फ़ीचर-डिटेक्ट करें और प्लगइन के बिना भी पेज को इस्तेमाल लायक रखें:

var SR = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenReader;

async function say(message) {
  if (SR) { await SR.speak({ value: message }); return; }
  document.getElementById('live-region').textContent = message;   // an aria-live="polite" element
}

ध्यान दें: language का डिफ़ॉल्ट 'en' है। ज़्यादातर घोषणाओं के लिए सामान्य एक्सेसिबल मार्कअप (लेबल, aria-live क्षेत्र) अपनाएँ; छोटे, ज़रूरी स्थिति बदलावों के लिए speak इस्तेमाल करें। स्क्रीन रीडर पहचानने का कोई वेब API नहीं है, इसलिए ब्राउज़र में can('screenReader') का जवाब 'none' है।

Capacitor.Share Capacitor#

Capacitor.Plugins.Share — share(options), canShare()

उदाहरण

शीर्षक, टेक्स्ट और/या लिंक के साथ Android शेयर शीट खोलता है (@capacitor/share 8.0.1).

लौटाता है: share() → Promise { activityType } (चुने गए ऐप का कॉम्पोनेंट नाम, '' हो सकता है); यूज़र के शीट बंद करने पर यह REJECT होता है। canShare() → Promise { value: boolean }। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

async function shareLink() {
  var Share = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Share;
  if (!Share) { alert('Sharing is not available here'); return; }
  // Only pass the fields you have. A present but empty `url` is rejected ("Unsupported url").
  var opts = { title: 'My list', text: 'Milk, eggs, bread' };
  var link = 'https://example.com/list/42';
  if (link) opts.url = link;
  try {
    var r = await Share.share(opts);
    console.log('shared to', r.activityType);
  } catch (e) {
    console.log('share cancelled or failed:', e.message);   // "Share canceled" on dismiss
  }
}

AI से बने ऐप में रैपर का रूप यही रहता है और रद्द करने पर भी reject होता है:

import { Share, can } from '@/lib/appmintNative';

if (can('share') !== 'none') {
  try {
    await Share.share({ title: 'My list', text: 'Milk, eggs, bread', url: 'https://example.com/list/42' });
  } catch {
    // the user closed the sheet — not an error to show
  }
}

पहले canShare() जाँचें और शेयरिंग उपलब्ध न हो तो बटन छिपा दें:

var Share = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Share;
var btn = document.getElementById('share');

btn.hidden = true;
if (Share) {
  Share.canShare().then(function (r) { btn.hidden = !r.value; });
}

ध्यान दें: url http(s):// या file:// होना चाहिए। dialogTitle चुनने वाली विंडो का शीर्षक तय करता है। फ़ाइलें शेयर करने के लिए ऐप के अपने file:// पाथ चाहिए; पेज से फ़ाइलें शेयर करने के लिए इसकी जगह navigator.share({ files }) इस्तेमाल करें। एक बार में सिर्फ़ एक शेयर खुला रह सकता है ("Can't share while sharing is in progress")।

Capacitor.SpeechRecognition Capacitor#

Capacitor.Plugins.SpeechRecognition

उदाहरण

Android के स्पीच रिकग्नाइज़र से यूज़र की आवाज़ को टेक्स्ट में बदलता है (कम्युनिटी @capacitor-community/speech-recognition प्लगइन, जो ऐप में शामिल है)। Android WebView में Web Speech रिकग्निशन नहीं है, इसलिए बोलकर लिखने का यही तरीका है।

लौटाता है: Promise। available() → { available }। checkPermissions() / requestPermissions() → { speechRecognition: 'granted' | 'denied' | 'prompt' }। start({ partialResults: false }) → यूज़र के बोलना बंद करने के बाद { status: 'success', matches: [...] }; बोलना न हो पाने या कुछ न मिलने जैसी त्रुटियों पर यह reject होता है। ज़रूरत: बिल्ड करते समय चरण 4 (Access) में Mic टिक करें (HTML, ZIP और AI से बने ऐप के लिए, जब आपकी फ़ाइलों में SpeechRecognition आता है तो बिल्ड माइक्रोफ़ोन अनुमति अपने आप भी जोड़ देता है), और यूज़र को माइक्रोफ़ोन की अनुमति देनी होगी। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

एक बार बोलकर लिखना (उसी तरह जैसे @/lib/appmintNative speech इसे इस्तेमाल करता है):

var SR = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.SpeechRecognition : null;

async function dictate() {
  var out = document.getElementById('text');
  if (!SR || !(await SR.available()).available) { out.textContent = 'Voice input is not available on this phone.'; return; }

  var p = (await SR.checkPermissions()).speechRecognition;
  if (p !== 'granted') p = (await SR.requestPermissions()).speechRecognition;
  if (p !== 'granted') { out.textContent = 'Microphone permission was not given.'; return; }

  try {
    var r = await SR.start({ language: 'en-US', maxResults: 3, partialResults: false, popup: false });
    out.textContent = r.matches && r.matches.length ? r.matches[0] : '';
  } catch (e) {
    out.textContent = 'Did not catch that. Try again.';
  }
}

document.getElementById('mic').addEventListener('click', dictate);

यूज़र के बोलते समय लाइव टेक्स्ट (partialResults: true), और सुनने की स्थिति:

// Add the listeners ONCE, when the page starts.
if (SR) {
  SR.addListener('partialResults', function (d) {
    // Words as they come, and then the final text, all arrive here.
    if (d.matches && d.matches.length) document.getElementById('text').textContent = d.matches[0];
  });
  SR.addListener('listeningState', function (d) {
    // 'started' = the user began speaking, 'stopped' = the user stopped speaking
    document.body.classList.toggle('listening', d.status === 'started');
  });
}

document.getElementById('mic-live').addEventListener('click', async function () {
  if (!SR) return;
  try {
    await SR.start({ language: 'en-US', partialResults: true, popup: false });   // resolves at once, no matches
  } catch (e) {
    document.getElementById('text').textContent = 'Could not start: ' + e.message;
  }
});

document.getElementById('stop').addEventListener('click', function () { if (SR) SR.stop(); });

माइक बटन तभी दिखाएँ जब बोलकर लिखना चल सके, और पेज छिपने पर सुनना बंद करें:

var SR = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.SpeechRecognition : null;
var mic = document.getElementById('mic');

mic.hidden = true;
if (SR) {
  SR.available().then(function (r) { mic.hidden = !r.available; });
}

document.addEventListener('visibilitychange', function () {
  if (document.hidden && SR) SR.stop();
});

ध्यान दें:

  • लाइव मोड (partialResults: true) में अंतिम टेक्स्ट 'stopped' स्थिति के बाद आता है, इसलिए 'stopped' पर partialResults लिसनर न हटाएँ। शुरू होने के बाद की त्रुटि (बोलना न हो पाना, कुछ न मिलना) इस मोड में नहीं बताई जाती।
  • language 'en-US' या 'ta-IN' जैसा टैग है (डिफ़ॉल्ट: फ़ोन की भाषा)। popup: true की जगह Google का अपना सुनने वाला डायलॉग दिखता है। getSupportedLanguages() → { languages } और isListening() → { listening } भी मौजूद हैं।
  • start() अगर आपने पहले अनुमति नहीं माँगी तो 'Missing permission' के साथ reject होता है। बोलने में ठहराव आने पर सुनना अपने आप रुक जाता है।

Capacitor.SplashScreen Capacitor#

Capacitor.Plugins.SplashScreen — show(), hide()

उदाहरण

ऐप की अपनी ब्रांडेड लॉन्च स्प्लैश के ऊपर @capacitor/splash-screen API, ताकि इम्पोर्ट किए गए Capacitor / AI Studio प्रोजेक्ट, जो पहली स्क्रीन तैयार होने पर SplashScreen.hide() कॉल करते हैं, Android ऐप में काम करें।

लौटाता है: hide() → Promise (क्रिएटर का न्यूनतम स्प्लैश समय बीतने पर स्प्लैश हटती है); show({showDuration, autoHide}) → Promise (स्प्लैश पेज के ऊपर वापस आती है और autoHide के साथ - जो डिफ़ॉल्ट है - showDuration ms बाद हट जाती है, डिफ़ॉल्ट 3000)। ज़रूरत: चालू करने के लिए कुछ नहीं।

const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;

async function boot() {
  await loadFirstScreen();
  if (Splash) await Splash.hide();     // otherwise the shell hides it at first paint
}
boot();

धीमे अकाउंट स्विच को स्प्लैश से ढकें, नया डेटा स्क्रीन पर आने तक उसे रखें:

const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;

async function switchAccount(accountId) {
  if (Splash) await Splash.show({ autoHide: false });   // stays until hide()
  try {
    await loadAccount(accountId);
    renderHome();
  } finally {
    if (Splash) await Splash.hide();
  }
}

साइन आउट के बाद कुछ देर के लिए ब्रांडेड स्प्लैश दिखाएँ; यह अपने आप हट जाती है showDuration:

const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;

async function signOut() {
  await clearSession();
  showSignInScreen();
  if (Splash) {
    try {
      await Splash.show({ showDuration: 1200 });
    } catch (e) {
      console.warn('splash not shown:', e.code);
    }
  }
}

ध्यान दें: hide() कॉल के बिना भी स्प्लैश पहले पेंट पर हट जाती है, हर ऐप की तरह। AI से बने ऐप splash.hold() / splash.ready() इस्तेमाल करते हैं, यहाँ से @/lib/appmintNative.

Capacitor.StatusBar Capacitor#

Capacitor.Plugins.StatusBar — setStyle, setBackgroundColor, show, hide, getInfo

उदाहरण

स्टेटस बार के आइकन की शैली, रंग और दिखना बदलता है (@capacitor/status-bar 8.0.2).

लौटाता है: हर तरीका → Promise void, सिवाय getInfo() → { visible, style, color, overlays, height }। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

style उस बैकग्राउंड का नाम बताता है जिसके लिए यह ठीक है: 'DARK' = हल्के आइकन (गहरे बार के लिए), 'LIGHT' = गहरे आइकन, 'DEFAULT' = सिस्टम के हिसाब से।

var StatusBar = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.StatusBar;
if (StatusBar) {
  StatusBar.setStyle({ style: 'DARK' });          // light icons
  StatusBar.hide();                               // e.g. while a video plays
  // later
  StatusBar.show();
}

बार का रंग शेल ब्रिज से बदलें, प्लगइन से नहीं। Android 15+ पर प्लगइन का setBackgroundColor कुछ नहीं करता (edge-to-edge इसे अनदेखा करता है)। शेल पट्टी खुद रंगता है और उसी कॉल में आइकन शैली भी लेता है:

if (window.WebToApk && window.WebToApk.setStatusBarColor) {
  window.WebToApk.setStatusBarColor('#0B0F1A', 'light');   // dark bar, light icons
} else if (StatusBar) {
  StatusBar.setBackgroundColor({ color: '#0B0F1A' });      // hex only, e.g. #RRGGBB
}

AI से बने ऐप में setStatusBar(color, contentStyle) इस्तेमाल करें; यह शेल ब्रिज को प्राथमिकता देता है और रंग व आइकन एक ही कॉल में सेट करता है:

import { setStatusBar, StatusBar } from '@/lib/appmintNative';

setStatusBar('#0B0F1A', 'light');                       // dark bar, light icons
await StatusBar.setBackgroundColor({ color: '#FFFFFF' }); // colour only; icons picked from luminance

ध्यान दें: setBackgroundColor ऐसे रंग को reject करता है जो hex स्ट्रिंग नहीं है। फ़ुलस्क्रीन / कियोस्क बिल्ड में बार शेल छिपा देता है। Android ऐप में अकेले रैपर का StatusBar.setStyle() कुछ नहीं बदलता (ब्रिज को रंगने के लिए रंग चाहिए) - शैली को रंग के साथ setStatusBar() में दें।

Capacitor.TextToSpeech Capacitor#

Capacitor.Plugins.TextToSpeech — speak(), stop(), getSupportedLanguages(), getSupportedVoices()

उदाहरण

फ़ोन के टेक्स्ट-टू-स्पीच इंजन पर बना कम्युनिटी @capacitor-community/text-to-speech प्लगइन। इसे पहले से शामिल किया गया है ताकि इसे कॉल करने वाले इम्पोर्ट किए गए Capacitor प्रोजेक्ट काम करें।

लौटाता है: speak({text, lang, rate, pitch, volume, voice}) → ऐसा Promise जो वाक्य बोले जाने पर resolve होता है; stop(); getSupportedLanguages() → {languages}; getSupportedVoices() → {voices}; isLanguageSupported({lang}) → {supported}। ज़रूरत: चालू करने के लिए कुछ नहीं।

const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;

async function readAloud(text) {
  if (!Tts) { speechSynthesis.speak(new SpeechSynthesisUtterance(text)); return; }
  await Tts.speak({ text: text, lang: 'en-US', rate: 1.0, pitch: 1.0, volume: 1.0 });
}
document.getElementById('stop').onclick = () => Tts && Tts.stop();

बोलने से पहले भाषा जाँचें और इंस्टॉल न होने पर संदेश दिखाएँ:

const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;

async function speakIn(lang, text) {
  if (!Tts) return false;
  const { supported } = await Tts.isLanguageSupported({ lang: lang });
  if (!supported) { showMessage('This phone has no ' + lang + ' voice installed.'); return false; }
  await Tts.speak({ text: text, lang: lang });
  return true;
}

स्टॉप बटन के साथ एक पैराग्राफ़ ज़ोर से पढ़ें, और बोलने की त्रुटि संभालें:

const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;

async function readParagraph(el, btn) {
  if (!Tts) return;
  btn.textContent = 'Stop';
  btn.onclick = () => Tts.stop();
  try {
    await Tts.speak({ text: el.textContent, lang: 'en-US', rate: 0.9 });   // resolves when finished
  } catch (e) {
    console.warn('could not speak:', e.message);
  } finally {
    btn.textContent = 'Listen';
    btn.onclick = () => readParagraph(el, btn);
  }
}

ध्यान दें: window.speechSynthesis ऐप में भी चलता है (शेल का अपना इंजन) और AI से बने ऐप इसे speak() के ज़रिए इस्तेमाल करते हैं; यह प्लगइन Capacitor जैसा रास्ता है।

Capacitor.TextZoom Capacitor#

Capacitor.Plugins.TextZoom — get(), getPreferred(), set({ value })

उदाहरण

ऐप के पेज का टेक्स्ट साइज़ पढ़ता और बदलता है, ऐप के अंदर "टेक्स्ट साइज़" कंट्रोल के लिए (@capacitor/text-zoom 8.0.1).

लौटाता है: get() → Promise { value } (मौजूदा ज़ूम, 1 = 100%)। getPreferred() → { value } (वह साइज़ जो यूज़र ने Android सेटिंग्स में चुना है)। set({ value }) → Promise void। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var TZ = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextZoom;

async function biggerText() {
  if (!TZ) return;
  var now = (await TZ.get()).value;
  await TZ.set({ value: Math.min(2, now + 0.1) });
}

async function resetText() {
  if (!TZ) return;
  var pref = (await TZ.getPreferred()).value;   // e.g. 1.15 when the phone uses large text
  await TZ.set({ value: pref });
}

AI से बने ऐप में (वेब पर यह इसकी जगह रूट फ़ॉन्ट साइज़ बदलता है):

import { textZoom } from '@/lib/appmintNative';

const size = await textZoom.get();
await textZoom.set(size + 0.1);                     // clamped to 0.5–3
await textZoom.set(await textZoom.getPreferred());  // back to the system size

टेक्स्ट साइज़ स्लाइडर जो चुनाव को याद रखता है:

var TZ = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextZoom;
var slider = document.getElementById('text-size');   // <input type="range" min="0.8" max="1.6" step="0.1">

if (TZ) {
  var saved = parseFloat(localStorage.getItem('textZoom'));
  if (saved) TZ.set({ value: saved });
  slider.addEventListener('change', function () {
    TZ.set({ value: parseFloat(slider.value) });
    localStorage.setItem('textZoom', slider.value);
  });
} else {
  slider.hidden = true;
}

ध्यान दें: ऐप पहले से सिस्टम का टेक्स्ट साइज़ मानता है; यह ऐप के अंदर अलग से कंट्रोल देने के लिए है। अपना लेआउट बड़े साइज़ पर टेस्ट करें - टेक्स्ट कंट्रोल की तय ऊँचाई टेक्स्ट को काट देगी।

Capacitor.Toast Capacitor#

Capacitor.Plugins.Toast — show({ text, duration, position })

उदाहरण

Android का छोटा सिस्टम टोस्ट दिखाता है, जैसे "Saved" या "Copied" (@capacitor/toast 8.0.1).

लौटाता है: Promise void। ज़रूरत: चालू करने के लिए कुछ नहीं - हर ऐप में प्लगइन मौजूद होता है। window.Capacitor सिर्फ़ उन पेजों पर होता है जिन्हें ऐप खुद चलाता है (HTML, ZIP और AI से बने ऐप)। वेबसाइट मोड का ऐप किसी दूसरी साइट को लोड करता है, और उस साइट को window.Capacitor कभी नहीं मिलता - फ़ीचर-डिटेक्ट करें।

var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;

function saved() {
  if (Toast) Toast.show({ text: 'Saved', duration: 'short', position: 'bottom' });
}

duration है 'short' (लगभग 2 सेकंड) या 'long' (लगभग 3.5 सेकंड)। position है 'top', 'center' या 'bottom'.

AI से बने ऐप में toast() या Capacitor जैसा Toast इस्तेमाल करें; वेब पर ये ऐप के रंगों में स्नैकबार बनाते हैं:

import { Toast, toast } from '@/lib/appmintNative';

await Toast.show({ text: 'Added to list', duration: 'long' });
toast('Copied');   // short form, same result

फ़ीचर-डिटेक्ट करें और प्लगइन न होने पर पेज में संदेश दिखाएँ:

function notify(message) {
  var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
  if (Toast) { Toast.show({ text: message, duration: 'short' }); return; }
  var el = document.getElementById('snackbar');   // a plain in-page message
  el.textContent = message;
  el.hidden = false;
  setTimeout(function () { el.hidden = true; }, 2000);
}

ध्यान दें: text ज़रूरी है ("Must provide text")। टोस्ट सिस्टम फ़ोन बनाने वाली कंपनी की शैली में दिखाता है, और नए Android वर्ज़न टेक्स्ट टोस्ट के लिए position को अनदेखा करते हैं। टोस्ट आसानी से छूट जाता है - जिस त्रुटि पर यूज़र को कुछ करना है, उसके लिए इसे कभी इस्तेमाल न करें; उसके लिए Dialog.alert इस्तेमाल करें।

Capacitor.Torch Capacitor#

Capacitor.Plugins.Torch — enable(), disable(), toggle(), isEnabled(), isAvailable()

उदाहरण

फ़ोन का फ़्लैशलाइट, @capawesome/capacitor-torch API के साथ। ऐप शेल का अपना प्लगइन (TorchPlugin.kt).

लौटाता है: enable() / disable() / toggle() → Promise (ऐप की अपनी कैमरा स्ट्रीम खुली होने पर CAMERA_IN_USE के साथ reject, फ़्लैश न होने पर UNAVAILABLE के साथ); isEnabled() → {enabled}; isAvailable() → {available}। ज़रूरत: चालू करने के लिए कुछ नहीं और कोई अनुमति नहीं।

const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;

async function setupLightButton() {
  if (!Torch || !(await Torch.isAvailable()).available) { lightBtn.hidden = true; return; }
  lightBtn.onclick = async () => {
    try {
      await Torch.toggle();
      lightBtn.classList.toggle('on', (await Torch.isEnabled()).enabled);
    } catch (e) {
      alert(e.message);
    }
  };
}

बटन से SOS सिग्नल की फ़्लैश चलाएँ, और अगर बीच में कैमरा फ़्लैश ले ले तो लाइट बंद कर दें:

const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
const wait = (ms) => new Promise((r) => setTimeout(r, ms));

sosBtn.onclick = async () => {
  if (!Torch || !(await Torch.isAvailable()).available) return;
  const flashes = [200, 200, 200, 600, 600, 600, 200, 200, 200];   // S O S, in ms
  try {
    for (const ms of flashes) {
      await Torch.enable();  await wait(ms);
      await Torch.disable(); await wait(200);
    }
  } catch (e) {
    await Torch.disable().catch(() => {});
    alert(e.code === 'CAMERA_IN_USE' ? 'Close the camera first.' : e.message);
  }
};

लाइट बटन को सिस्टम के साथ मिलाकर रखें, क्योंकि ऐप के बैकग्राउंड में होने पर भी यूज़र क्विक-सेटिंग्स टाइल से फ़्लैशलाइट बदल सकता है:

const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;

async function syncLightButton() {
  if (!Torch) return;
  const { enabled } = await Torch.isEnabled();
  lightBtn.classList.toggle('on', enabled);
  lightBtn.setAttribute('aria-pressed', String(enabled));
}

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') syncLightButton();
});
syncLightButton();

ध्यान दें: लाइट सिस्टम की स्थिति के हिसाब से चलती है (क्विक-सेटिंग्स टाइल से बंद करने पर वह बंद पढ़ी जाती है) और ऐप बंद होने पर बंद हो जाती है। getUserMedia स्ट्रीम खुली होने पर लाइट को ट्रैक से जलाएँ: track.applyConstraints({ advanced: [{ torch: true }] })। AI से बने ऐप torch इस्तेमाल करते हैं, यहाँ से @/lib/appmintNative.

हर डॉक्स बिल्ड पर ऐप रनटाइम और उसकी उदाहरण फ़ाइलों से बनाया जाता है। Markdown में पढ़ें · सभी फ़ैमिली.

2026-10-03 को शिप किए गए ब्रिज से मिलाकर जाँचा गया।