تطبيق الويب التقدمي (Progressive web application) ويسمى اختصارًا بـ (PWA) هو أحد أنواع التطبيقات التي تعمل عبر الويب مع قابليتها للتثبيت علي الأجهزة الجوالة، وتكون هذه التطبيقات مبنية باستخدام تقنيات الويب بما في ذلك جافاسكربت وHTML وكذلك CSS، بهدف صنع تطبيق يعمل على مختلف الأنظمة التي تتضمن متصفحات تُطابق المعايير، بما في ذلك أجهزة سطح المكتب وكذلك الهواتف الذكية.
تطبيق الويب التقدمي (PWA)
إذن تطبيق الويب PWA ليس تقنية أو إطار عمل جافاسكريبت جديد، وإنما مجموعة من الممارسات الجيدة والمزايا التي يجب أن تتوفر في تطبيق الويب ليكون شبيها بتطبيقات الهواتف الذي اعتدنا تحميلها من متجر Play Store بالنسبة لهواتف أندرويد و App Store بالنسبة لهواتف وأجهزة شركة Apple. الهدف هو منح مستخدمي تطبيقات الويب تجربة استخدام تماثل تلك الموجودة في Native Applications. يفترض في هذا النوع من التطبيقات أن تعمل بشكل جيد في كافة الأجهزة على اختلاف مقوماتها وإمكاناتها التقنية. قد لا يكون بالإمكان مثلا إتاحة بعض المزايا والوظائف في بعض الهواتف أو الأجهزة القديمة، ولكن يجب ضمان أن يظل التطبيق يعمل فيها بشكل جيد وبالخصوص من ناحية الأداء والسرعة ونظراً للمزايا هذا أن كونت تملك مدونة بلوجر أو موقع ويب يجب عليك تثبيت تطبيق PWA علي موقعك الإلكتروني
خطوات إنشاء PWA لـ Blogger
من أجل إنشاء تطبيق ويب تقدمي ، ستحتاج إلى إضافة بعض الميزات إلى موقع الويب الخاص بك. مما يسمح لموقعك بالعمل دون اتصال بالإنترنت ، ودفع الإشعارات عند عودة المستخدمين إلى موقعك. يمكنك أيضًا تثبيت رسالة Add-to-Home على موقع الويب الخاص بك والتي تطالب المستخدمين بإضافة موقعك أو تطبيقك إلى الشاشة الرئيسية على أجهزتهم المحمولة أو أجهزة الكمبيوتر.
متطلبات
قبل أن نبدأ ، هناك العديد من الأشياء التي يجب أن تكون مطلوبة لتفعيل PWA :-
- يجب تجهيز شعار مدونتك بحجم 512 × 512 .png
- يجب أن يكون لديك حساب على GitHub
- يجب أن تمر المدونة عبر إدارة DNS: Cloudflare
تحميل الأيقونات
- قم بإعداد رمز لمدونتك بحجم .png 512 × 512.
- إعادة تسمية الملف باسم android-icon-512x512.png
- انتقل إلى favicon-generator.org وقم بتحميل رمز المدونة.
- قم بتنزيل الأيقونة المفضلة التي تم إنشاؤها واستخراج الملفات.
- احذف الملفات غير الضرورية مثل:
- browserconfig.xml
- manifest.json
شاهد أيضاً :-
رفع الأيقونات علي GitHub
- قم بإنشاء مستودع على GitHub.com، على سبيل المثال icon-medoapp
- وقم بتحميل جميع ملفات الرموز في main الفرع.
- قم بتحميل الشعار مدونتك الأصلي أيضًا معهم ، أي android-icon-512x512.png.
- سيكون العدد الإجمالي للرموز حوالي 26.
انشاء خوادم Cloudflare
- 1- قم بتسجيل الدخول إلى حساب في Cloudflare.com.
- 2- انتقل إلى قسم العمال وانقر على إدارة العمال.
- 3- انقر فوق إنشاء خدمة وأعد تسمية الخدمة باسم
main-blogname
، على سبيل المثال main-medoapp. بعد احذف النصي البرامجي الحالي ، واستبدله بالنص التالي:
addEventListener("fetch", event => { event.respondWith(handleRequest(event)) }) //const BUCKET_NAME = "main" const BUCKET_URL = `https://cdn.statically.io/gh/Mr-medo-net/app-icon` async function serveAsset(event) { const url = new URL(event.request.url) const cache = caches.default let response = await cache.match(event.request) if (!response) { response = await fetch(`${BUCKET_URL}${url.pathname}`) const headers = { "cache-control": "public, max-age=14400" } response = new Response(response.body, { ...response, headers }) event.waitUntil(cache.put(event.request, response.clone())) } return response } async function handleRequest(event) { if (event.request.method === "GET") { let response = await serveAsset(event) if (response.status > 399) { response = new Response(response.statusText, { status: response.status }) } return response } else { return new Response("Method not allowed", { status: 405 }) } }
Manifest.json
بالطريقة نفسها ، أنشئ خدمة وأعد تسميتهاmanifest-blogname
، على سبيل المثال manifest-medoapp. استبدل الكود الموجود بالكود التالي:addEventListener("fetch", event => { const data = { name: "Master Medo Website", short_name: "Master Medo app", description: "قم بتحميل تطبيق موقعنا الالكتروني الان وتصفح احدث المشاركات بدون انترنت. - Install APP Now Mr-Medo.Net", display: "standalone", prefer_related_applications: false, start_url: "\/?utm_source=homescreen", scope: "\/", background_color: "#BA0000", theme_color: "#BA0000", icons: [ { src: "\/main\/android-icon-512x512.png", sizes: "512x512", type: "image\/png", density: "4.0", purpose: "any maskable" }, { src: "\/main\/android-icon-192x192.png", sizes: "192x192", type: "image\/png", density: "4.0", purpose: "any maskable" }, { src: "\/main\/apple-icon-144x144.png", sizes: "144x144", type: "image\/png", density: "3.0", purpose: "any maskable" }, { src: "\/main\/android-icon-96x96.png", sizes: "96x96", type: "image\/png", density: "2.0", purpose: "any maskable" }, { src: "\/main\/android-icon-72x72.png", sizes: "72x72", type: "image\/png", density: "1.5", purpose: "any maskable" }, { src: "\/main\/android-icon-48x48.png", sizes: "48x48", type: "image\/png", density: "1.0", purpose: "any maskable" }, { src: "\/main\/android-icon-36x36.png", sizes: "36x36", type: "image\/png", density: "0.75", purpose: "any maskable" } ], shortcuts: [ { name: "الصفحة الرئيسية", short_name: "Homepage", description: "Cyber1101 | دروس وشروحات دوت نت عالم الخبرة الرقمية.", url: "\/?utm_source=homescreen", icons: [ { src: "\/main\/home-icon-192x192.png", sizes: "192x192" } ] }, { name: "احدث المشاركات", short_name: "Blog", description: "احدث المشاركات.", url: "\/search?utm_source=homescreen", icons: [ { src: "\/main\/trend-icon-192x192.png", sizes: "192x192" } ] }, { name: "تطبيقات والعاب", short_name: "تطبيقات والعاب", description: "التطبيقات والالعاب.", url: "\/search\/label\/تطبيقات?utm_source=homescreen", icons: [ { src: "\/main\/appsm-icon-192x192.png", sizes: "192x192" } ] } ], screenshots: [ { src: "\/main\/scr1.png", type: "image\/png", sizes: "540x720" }, { src: "\/main\/scr2.png", type: "image\/png", sizes: "540x720" }, { src: "\/main\/scr3.png", type: "image\/png", sizes: "540x720" }, { src: "\/main\/scr4.png", type: "image\/png", sizes: "540x720" }, { src: "\/main\/scr5.png", type: "image\/png", sizes: "540x720" } ], serviceworker: { src: "\/sw.js" } } const json = JSON.stringify(data, null, 2) return event.respondWith( new Response(json, { headers: { "content-type": "application/json;charset=UTF-8" } }) ) })
استبدل الأجزاء المميزة بالون الاحمر حسب حاجتك. مع تغيير رمز اللون أيضًا. بعد انقر حفظ ونشر.
ServiceWorker
serviceworker-blogname
. استبدل الكود الموجود بالكود التالي:const js = ` importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js'); if (workbox) { workbox.core.skipWaiting(); workbox.core.clientsClaim(); workbox.core.setCacheNameDetails({ prefix: 'thn-sw', suffix: 'v22', precache: 'install-time', runtime: 'run-time' }); const FALLBACK_HTML_URL = '/offline.html'; const version = workbox.core.cacheNames.suffix; workbox.precaching.precacheAndRoute([{url: FALLBACK_HTML_URL, revision: null},{url: '/manifest.json', revision: null},{url: '/main/favicon.ico', revision: null}]); workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly()); workbox.routing.registerRoute( new RegExp('.(?:css|js|png|gif|jpg|svg|ico)$'), new workbox.strategies.CacheFirst({ cacheName: 'images-js-css-' + version, plugins: [ new workbox.expiration.ExpirationPlugin({ maxAgeSeconds: 60 * 24 * 60 * 60, maxEntries:200, purgeOnQuotaError: true }) ], }),'GET' ); workbox.routing.setCatchHandler(({event}) => { switch (event.request.destination) { case 'document': return caches.match(FALLBACK_HTML_URL); break; default: return Response.error(); } }); self.addEventListener('activate', function(event) { event.waitUntil( caches .keys() .then(keys => keys.filter(key => !key.endsWith(version))) .then(keys => Promise.all(keys.map(key => caches.delete(key)))) ); }); } else { console.log('Oops! Workbox did not load'); } ` async function handleRequest(request) { return new Response(js, { headers: { "content-type": "application/javascript;charset=UTF-8", }, }) } addEventListener("fetch", event => { return event.respondWith(handleRequest(event.request)) })
لقد استخدمنا Workbox ، حتى نتمكن من تخزين HTML و CSS و JS وأي ملفات ثابتة مؤقتًا.
انقر فوق حفظ ونشر.
غير متصل بالانترنت Offline
كما هو مذكور أعلاه ، أنشئ خدمة وأعد تسميتها كـoffline-blogname
، ie offline-medoapp.استبدل الكود الموجود بالكود التالي:
const html = `<!DOCTYPE html> <html> <head> <!--[ Meta Tags ]--> <title>Oops, You're Offline!</title> <meta charset='UTF-8'/> <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' name='viewport'/> <meta content='IE=edge' http-equiv='X-UA-Compatible'/> <!--[ Theme Color ]--> <meta content='#BA0000' name='theme-color'/> <meta content='#BA0000' name='msapplication-navbutton-color'/> <meta content='#BA0000' name='apple-mobile-web-app-status-bar-style'/> <meta content='true' name='apple-mobile-web-app-capable'/> <!--[ Favicon ]--> <link href='/main/apple-icon-120x120.png' rel='apple-touch-icon' sizes='120x120'/> <link href='/main/apple-icon-152x152.png' rel='apple-touch-icon' sizes='152x152'/> <link href='/main/favicon-32x32.png' rel='icon' sizes='32x32' type='image/png'/> <link href='/main/favicon-96x96.png' rel='icon' sizes='96x96' type='image/png'/> <link href='/main/favicon-16x16.png' rel='icon' sizes='16x16' type='image/png'/> <link href='/main/favicon.ico' rel='icon' type='image/x-icon'/> <link href='/main/favicon.ico' rel='shortcut icon' type='image/x-icon'/> <!--[ Stylesheet ]--> <style>/*<![CDATA[*/ /* Merriweather - Font */ @font-face{font-family: 'Merriweather'; font-style: italic; font-weight: 300; font-display: swap; src: local('Merriweather-LightItalic'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7lXff4jvw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7lXcf8.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: italic; font-weight: 700; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7NWPf4jvw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR71Wsf8.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: italic; font-weight: 900; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7NWPf4jvw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7NWMf8.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: normal; font-weight: 300; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l521wRZWMf6.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l521wRpXA.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: normal; font-weight: 700; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52xwNZWMf6.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52xwNpXA.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: normal; font-weight: 900; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52_wFZWMf6.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52_wFpXA.woff) format('woff')} /* Content */ body{background:#f1f3f6;color:#1f1f1f;font-family:'Merriweather',serif;font-weight:400;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body:focus{outline:none !important} .mainCont{margin:0 auto;position:fixed;left:0;top:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;padding:15px} .noIntPop{position:relative;overflow:hidden;text-align:center;padding:15px;border-radius:30px;background:#f1f3f6;box-shadow:inset 0 0 15px rgba(55, 84, 170, 0), inset 0 0 20px rgba(255, 255, 255, 0), 7px 7px 15px rgba(55, 84, 170, 0.15), -7px -7px 20px white, inset 0px 0px 4px rgba(255, 255, 255, 0.2)} .circle.t{top:-150px;right:-150px} .circle.b{bottom:-150px;left:-150px} .noIntCont{position:relative;z-index:1} .noIntIcon{padding:30px} .noConHead{font-weight:700;font-size:1.3rem} .noConDesc{font-size:16px;line-height:1.4em;padding-top:20px;font-weight:400;opacity:.8} .cta,.relCont{display:flex;justify-content:center;align-items:center} .relCont{padding:30px} .cta{width:66px;height:66px;background:#f1f3f6;outline:none;border:none;border-radius:690px;box-shadow:inset 0 0 15px rgba(55, 84, 170, 0), inset 0 0 20px rgba(255, 255, 255, 0), 7px 7px 15px rgba(55, 84, 170, 0.15), -7px -7px 20px white, inset 0px 0px 4px rgba(255, 255, 255, 0.2);transition:box-shadow 399ms ease-in-out} .cta:hover{box-shadow:inset 7px 7px 15px rgba(55, 84, 170, 0.15), inset -7px -7px 20px white, 0px 0px 4px rgba(255, 255, 255, 0.2)} .icon{content:'';width:25px;height:25px;display:inline-block} .iconB{content:'';width:50px;height:50px;display:inline-block} .icon.reload{background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239dabc0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='23 4 23 10 17 10'/><path d='M20.49 15a9 9 0 1 1-2.12-9.36L23 10'/></svg>") center / 25px no-repeat} .iconB.wifiOff{background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f1f1f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='1' y1='1' x2='23' y2='23'/><path d='M16.72 11.06A10.94 10.94 0 0 1 19 12.55'/><path d='M5 12.55a10.94 10.94 0 0 1 5.17-2.39'/><path d='M10.71 5.05A16 16 0 0 1 22.58 9'/><path d='M1.42 9a15.91 15.91 0 0 1 4.7-2.88'/><path d='M8.53 16.11a6 6 0 0 1 6.95 0'/><line x1='12' y1='20' x2='12.01' y2='20'/></svg>") center / 50px no-repeat} .circle{position:absolute;z-index:1;width:280px;height:280px;border-radius:50%;background-color:#f1f3f6;box-shadow:inset 8px 8px 12px #d1d9e6, inset -8px -8px 12px #f9f9f9} /*]]>*/</style> </head> <body> <div class='mainCont notranslate'> <div class='noIntPop'> <div class='circle t'></div> <div class='circle b'></div> <div class='noIntCont'> <div class='noIntIcon'> <i class='iconB wifiOff'></i> </div> <div class='noConHead'>Oops, You're Offline!</div> <div class='noConDesc'>يبدو أن هناك خطأ ما في اتصالك بالإنترنت..</div> <div class='relCont'> <button class='cta' onclick='window.location.reload()'> <i class='icon reload'></i> </button> </div> </div> </div> </div> </body> </html>` async function handleRequest(request) { return new Response(html, { headers: { "content-type": "text/html;charset=UTF-8", }, }) } addEventListener("fetch", event => { return event.respondWith(handleRequest(event.request)) })
استبدل الأجزاء المميزة حسب رغبتك. انقر حفظ ونشر.
انشاء مسارات للخوادم Creating Routes
أدخل الحقول كما هو موضح في الجدول اسفل:
Route | Service | Environment |
---|---|---|
www.mr-medo.net/main/* | main-medoapp | production |
www.mr-medo.net/manifest.json | manifest-medoapp | production |
www.mr-medo.net/sw.js | serviceworker-medoapp | production |
www.mr-medo.net/offline.html | offline-medoapp | production |
أدخل الحقول حسب عنوان URL الخاص باسم مدونتك.
تحرير اكواد قالب المدونة
انتقل الآن إلى Blogger Dashboard.انقر فوق تحرير HTML.
الصق الرموز التالية أدناه
<head>
، إذا لم تجدها ، فمن المحتمل أن يكون قد تم تحليلها وهو <head>. .
<link href='/main/apple-icon-57x57.png' rel='apple-touch-icon' sizes='57x57'/> <link href='/main/apple-icon-60x60.png' rel='apple-touch-icon' sizes='60x60'/> <link href='/main/apple-icon-72x72.png' rel='apple-touch-icon' sizes='72x72'/> <link href='/main/apple-icon-76x76.png' rel='apple-touch-icon' sizes='76x76'/> <link href='/main/apple-icon-114x114.png' rel='apple-touch-icon' sizes='114x114'/> <link href='/main/apple-icon-120x120.png' rel='apple-touch-icon' sizes='120x120'/> <link href='/main/apple-icon-114x114.png' rel='apple-touch-icon' sizes='144x144'/> <link href='/main/apple-icon-152x152.png' rel='apple-touch-icon' sizes='152x152'/> <link href='/main/apple-icon-180x180.png' rel='apple-touch-icon' sizes='180x180'/> <link href='/main/android-icon-192x192.png' rel='icon' sizes='192x192' type='image/png'/> <link href='/main/favicon-32x32.png' rel='icon' sizes='32x32' type='image/png'/> <link href='/main/favicon-96x96.png' rel='icon' sizes='96x96' type='image/png'/> <link href='/main/favicon-16x16.png' rel='icon' sizes='16x16' type='image/png'/> <link href='/main/favicon.ico' rel='icon' type='image/x-icon'/> <meta content='#BA0000' name='msapplication-TileColor'/> <meta content='/main/ms-icon-144x144.png' name='msapplication-TileImage'/> <meta content='#BA0000' name='theme-color'/> <link href='/manifest.json' rel='manifest'/>
أضف كود Javascript التالي أعلاه </body>
<script>/*<![CDATA[*/ let deferredPrompt; window.addEventListener('beforeinstallprompt', (e) => { deferredPrompt = e; }); const installApp = document.getElementById('installApp'); installApp.addEventListener('click', async () => { if (deferredPrompt !== null) { deferredPrompt.prompt(); const { outcome } = await deferredPrompt.userChoice; if (outcome === 'accepted') { deferredPrompt = null; } } }); /* Service Worker */ if('serviceWorker' in navigator){window.addEventListener('load',()=>{navigator.serviceWorker.register('/sw.js').then(registration=>{console.log('ServiceWorker registeration successful')}).catch(registrationError=>{console.log('ServiceWorker registration failed: ', registrationError)})})}; /*]]>*/</script>
وهذا زر استدعاء تحميل التطبيق يمكنك تضمينه في اي مكان تريد
<button id="installApp">Install</button>
أتمنى أن تستمتع بهذه المقالة. PWA (تطبيق ويب تقدمي) لموقع الويب الخاص بك على Blogger. وإذا كنت تواجه مشكلة أو كان لديك أي سؤال ، فاسألنا في مربع التعليقات . شكرًا لكم !
المصدر:-
www.fineshopdesign.com
ينتهي هنا موضوعنا عن "كيفية إنشاء تطبيق ويب تقدمي PWA لمدونات بلوجر"، ونلتقي في موضوع جديد على مدونة Cyber1101. دمتم في امان الله :)