JavaScript API
التطبيقات المبنية بـ Free HTML to APK تحقن جسرًا أصليًا باسم window.FreeApp. استدعِه من JavaScript العادي أو من React أو Vue أو من محرك ألعاب. تظل صفحتك تعمل في متصفح عادي إذا حميتَ الاستدعاءات.
البدء
قد يصل الجسر بعد لحظة من تشغيل نصوصك البرمجية، لذا أجرِ الإعداد الأصلي في الحدث freeappready، وكذلك فورًا إذا كان window.FreeApp موجودًا بالفعل. وفّر دائمًا بديلًا للمتصفح.
function setup() { FreeApp.statusBar('#E2552A'); FreeApp.toast('Hello from Android'); } if (window.FreeApp) setup(); else window.addEventListener('freeappready', setup, { once: true }); document.querySelector('#buzz').onclick = () => window.FreeApp ? FreeApp.vibrate(40) : console.log('Not in the app');
الاستدعاءات التي تحتاج إذنًا (الكاميرا، الميكروفون، الموقع، الإشعارات) تسأل المستخدم في المرة الأولى. فعّل الإذن المطابق في خطوة الأذونات في المنشئ؛ والقوالب تفعّل ما يستخدمه كودها.
التغذية الراجعة والواجهة
FreeApp.brightness(level: number): voidمن 0.0 إلى 1.0 لهذه النافذة، والقيمة السالبة تعيد سطوع النظام.
FreeApp.fullscreen(on: boolean): voidأخفِ أشرطة النظام (وضع الانغماس).
FreeApp.keepAwake(on: boolean): voidأبقِ الشاشة قيد التشغيل.
FreeApp.notify(title: string, body?: string): voidإشعار محلي فوري (يطلب الإذن على Android 13 وما بعده).
FreeApp.orientation(value: 'portrait' | 'landscape' | 'sensor_portrait' | 'sensor_landscape' | 'sensor' | 'unspecified'): voidFreeApp.print(): voidاطبع الصفحة / احفظها بصيغة PDF.
FreeApp.scheduleNotification(title: string, body: string, delayMs: number, opts?: {id?: number, url?: string, repeatMs?: number, exact?: boolean}): numberتُرجع المعرّف.
FreeApp.speak(text: string, lang?: string): voidتحويل النص إلى كلام أصلي، اللغة مثل 'en-US'.
FreeApp.statusBar(hexColor: string): voidمثال: '#2563EB'.
FreeApp.stopSpeaking(): voidFreeApp.toast(message: string): voidرسالة toast أصلية قصيرة.
FreeApp.vibrate(ms?: number | number[]): voidاهتزازة واحدة (الافتراضي 50 مللي ثانية) أو نمط [إيقاف، تشغيل، إيقاف، تشغيل…].
الكاميرا والمسح
FreeApp.camera.capture(opts?: {maxSize?: number, quality?: number, mirror?: boolean}): Promise<{dataUrl, facing}>صورة ثابتة من المعاينة الجارية.
FreeApp.camera.start(opts?: {facing?: 'back' | 'front', element?: string | Element /* place the preview over this element */, behind?: boolean /* draw under a transparent page so HTML controls float on top */}): Promise<{facing}>FreeApp.camera.switch(): Promise<{facing}>; FreeApp.camera.torch(on: boolean): boolean; FreeApp.camera.stop(): void; FreeApp.camera.isOpen(): booleanFreeApp.compressImage(dataUrl: string, opts?: {maxSize?: number, quality?: number}): Promise<{dataUrl, width, height, bytes}>أصلي، وسريع على الهواتف منخفضة المواصفات.
FreeApp.saveToGallery(dataUrl: string, fileName?: string): Promise<{uri}>تحفظ صورة في الصور.
FreeApp.scanCode(opts?: {formats?: string[] /* e.g. ['QR_CODE','EAN_13','CODE_128'] */, facing?: 'back' | 'front'}): Promise<{text, format}>ماسح QR / باركود أصلي بملء الشاشة مع مصباح؛ يُرفض بـ 'cancelled'.
FreeApp.torch(on: boolean): booleanالمصباح، يُرجع false إذا لم يكن هناك فلاش.
الموقع والمستشعرات
FreeApp.address(lat: number, lng: number): Promise<{address, city, country, countryCode, postalCode, street}>FreeApp.compass(cb: (d: {heading: number /* degrees */, pitch: number, roll: number}) => void): (() => void) | nullتُرجع دالة إيقاف.
FreeApp.location(opts?: {maxAge?: number}): Promise<{lat, lng, accuracy, altitude, speed, provider, time, fromLastKnown}>FreeApp.maps(query: string): voidافتح مكانًا أو "lat,lng" في تطبيق الخرائط.
FreeApp.sensors.start(type: 'accelerometer' | 'gyroscope' | 'magnetometer' | 'light' | 'proximity' | 'pressure' | 'gravity' | 'linear_acceleration' | 'rotation' | 'humidity' | 'temperature' | 'steps' | 'step_detector', cb: (d: {type, values: number[], x, y, z, accuracy, t}) => void, intervalMs?: number): (() => void) | nullتُرجع دالة إيقاف، أو null إذا لم تكن متاحة.
FreeApp.sensors.stop(type: string): voidFreeApp.watchLocation(cb: (p) => void, opts?: {interval?: number, distance?: number}): () => voidتُرجع دالة إيقاف.
الجهاز والتطبيق
FreeApp.app(): {packageName, versionName, versionCode, name, firstInstall}FreeApp.battery(): {level: number /* 0-100 */, charging: boolean}FreeApp.biometric(title: string, subtitle?: string): Promise<boolean>فتح القفل ببصمة الإصبع / الوجه.
FreeApp.device(): {manufacturer, model, brand, androidVersion, sdkInt, language, screenWidth, screenHeight, density, isTablet, darkMode}FreeApp.launchUrl(): string | nullالرابط العميق الذي فتح التطبيق.
FreeApp.network(): 'wifi' | 'cellular' | 'ethernet' | 'vpn' | 'other' | 'none' | 'unknown'FreeApp.on('deeplink', (d: {url}) => void): () => voidالروابط التي فُتحت أثناء تشغيل التطبيق.
FreeApp.online(): booleanالملفات والمشاركة والتخزين
FreeApp.copy(text: string): voidالنسخ إلى الحافظة.
FreeApp.open(url: string): voidافتح في المتصفح / التطبيق الخارجي.
FreeApp.paste(): stringاقرأ نص الحافظة.
FreeApp.pickFile(opts?: {accept?: string[], multiple?: boolean}): Promise<{name, mime, size, dataUrl}>FreeApp.saveFile(name: string, mime: string, data: string /* base64 or data: URL */ | Blob): Promise<boolean>تحفظ في التنزيلات؛ FreeApp.on('saved', d => …) يعطي {name, ok, location}.
FreeApp.store.get(key: string): any | nullFreeApp.store.set(key: string, value: any): voidتخزين أصلي دائم بنظام مفتاح/قيمة (JSON).
NFC
FreeApp.nfc.read(): Promise<{tagId, techs: string[], writable, maxSize, records: Array<{type: "text" | "uri" | "mime" | "unknown", value, mime?, lang?}>}>تنتظر وسمًا؛ FreeApp.nfc.stop() يلغي ذلك.
FreeApp.nfc.status(): 'ready' | 'disabled' | 'unsupported' | 'not_enabled_in_app'FreeApp.nfc.write(records: string | Array<{type: 'text' | 'uri' | 'mime', value: string, mime?: string}>): Promise<{written}>الأذونات
FreeApp.hasPermission(name: string): booleanFreeApp.openSettings(): voidافتح صفحة إعدادات النظام لهذا التطبيق.
FreeApp.permissionStatus(name: 'camera' | 'microphone' | 'location' | 'notifications' | 'activity'): 'granted' | 'prompt' | 'blocked' | 'unavailable'FreeApp.requestPermission(name: 'camera' | 'microphone' | 'location' | 'notifications'): Promise<boolean>FreeApp.requestPermissions(names: string[]): Promise<{[name]: boolean}>الإعلانات
متاح عند تفعيل AdMob في المنشئ. في وضع الاختبار تُعرض إعلانات Google التجريبية.
FreeApp.ads.loadBanner(unit?: string, position?: 'top' | 'bottom'): voidحمّل لافتة وأظهرها. بدون معاملات تستخدم الوحدة والموضع المحددين في المنشئ.
FreeApp.ads.showBanner(position?) / hideBanner() / isBannerLoaded()أظهر اللافتة أو أخفِها أو تحقق منها.
FreeApp.ads.loadInterstitial(unit?) / showInterstitial() / isInterstitialLoaded()إعلانات بملء الشاشة بين الشاشات. يتم فرض حد أدنى للفاصل بين إعلانات ملء الشاشة.
FreeApp.ads.loadRewarded(unit?) / isRewardedLoaded()حمّل إعلانًا بمكافأة مسبقًا.
FreeApp.ads.showRewarded(): Promise<{ok, amount, type}>تعرض إعلانًا بمكافأة؛ يكتمل عندما يحصل المستخدم على المكافأة، ويُرفض إذا أغلقه مبكرًا.
FreeApp.ads.privacyOptionsRequired(): boolean / showPrivacyOptions()تتيح للمستخدمين تغيير خيارات الموافقة (مطلوب في بعض المناطق).
FreeApp.ads.adapterStatus(): {[network]: {installed, configured, ready, description, latencyMs}}مع الوساطة: أي شبكات الشركاء موجودة داخل التطبيق وأيها أعدّها حساب AdMob الخاص بك.
FreeApp.ads.openAdInspector(): voidيفتح Ad Inspector من Google على أجهزة الاختبار.
FreeApp.ads.on(cb: (event) => void): () => voidأحداث الإعلانات مثل initialized وbannerLoaded وinterstitialDismissed وrewardedFailed. تُرجع دالة إلغاء الاشتراك.
مع شراء "إزالة الإعلانات"، تتوقف إعلانات اللافتة والإعلانات بملء الشاشة ويُطلق الحدث adFree. تستمر الإعلانات بمكافأة في العمل، لأن المستخدمين يختارون مشاهدتها.
الشراء داخل التطبيق
متاح عند تفعيل المشتريات في أداة الإنشاء. بِع منتجات لمرة واحدة، ومنتجات استهلاكية مثل العملات، واشتراكات عبر حساب Google Play الخاص بك. أنشئ المنتجات في Play Console أولًا بالمعرّفات نفسها. تعمل المشتريات في نسخة مثبّتة من Google Play، لذا اختبر باستخدام مسار اختبار ومختبِر ترخيص.
const billing = window.FreeApp && FreeApp.billing; if (billing && billing.isOwned('pro_unlock')) unlockPro(); // Unlock in the purchase event: it also arrives for purchases finished while the app was closed. billing && billing.on(e => { if (e.event === 'purchase' && e.id === 'pro_unlock') unlockPro(); }); buyButton.onclick = async () => { try { await billing.buy('pro_unlock'); } catch (err) { if (err.code === 'pending') show('Payment pending'); else if (err.code !== 'cancelled') show('Purchase failed'); } };
FreeApp.billing.products(ids: string[]): Promise<Product[]>التفاصيل المباشرة لمنتجاتك من Google Play: العنوان، والسعر المحلي، والعملة، وللاشتراكات فترة الفوترة والعروض. تُستبعد المعرّفات التي لا يعرفها Play.
FreeApp.billing.buy(id: string, opts?: {offer?: string}): Promise<Purchase>يفتح نافذة الدفع في Google Play. للاشتراك، يختار offer خطة أساسية أو معرّف عرض. يُرفض مع خطأ رمزه cancelled أو pending أو not_found أو unavailable أو busy أو network أو developer_error.
FreeApp.billing.owned(): string[] / isOwned(id): booleanما يمتلكه المستخدم، محفوظًا على الهاتف، فيأتي الرد فورًا وحتى دون اتصال. استخدمه عند بدء التشغيل لفتح الميزات المدفوعة.
FreeApp.billing.restore(): Promise<{purchases, owned}>يسأل Google Play مجددًا عن كل ما يمتلكه المستخدم، لزر استعادة المشتريات.
FreeApp.billing.consume(idOrToken: string): Promiseيستهلك منتجًا لمرة واحدة ليمكن شراؤه مرة أخرى. المنتجات المدرجة كاستهلاكية في أداة الإنشاء تُستهلك تلقائيًا.
FreeApp.billing.isAdFree(): booleantrue عندما يمتلك المستخدم أحد منتجات "إزالة الإعلانات" المحددة في أداة الإنشاء. عندها يوقف التطبيق إعلانات اللافتة والإعلانات بملء الشاشة تلقائيًا.
FreeApp.billing.manageSubscriptions(id?: string): voidيفتح شاشة الاشتراكات في Google Play، حيث يلغي المستخدمون خطتهم أو يغيّرونها.
FreeApp.billing.on(cb: (event) => void): () => voidأحداث الشراء: purchase (افتح الميزة هنا)، وpending، وowned (تغيّرت قائمة الممتلكات: شراء أو استرداد أو اشتراك منتهٍ)، وfailed، وunavailable. يُرجع دالة لإلغاء الاشتراك في الأحداث.
طبقة التوافق
الصفحات المكتوبة لأدوات HTML-to-APK الأخرى التي تستدعي window.AndroidAPI تظل تعمل: أسماء الدوال ومعرّفات الاستدعاء وأسماء الأحداث نفسها مدعومة، واستدعاءات الإعلانات آمنة وبلا أثر في التطبيقات التي لا تحتوي على إعلانات.