PWA (Progressive Web App) — είναι μια διαδικτυακή εφαρμογή που χρησιμοποιεί τις σύγχρονες δυνατότητες του προγράμματος περιήγησης για να λειτουργεί σαν εγγενής εφαρμογή: φορτώνει γρήγορα, λειτουργεί εκτός σύνδεσης, στέλνει ειδοποιήσεις push και εγκαθίσταται στην αρχική οθόνη. Στη βάση του PWA βρίσκονται τρεις τεχνολογίες: Service Worker, manifest και HTTPS. Service Worker — είναι ένα σενάριο που το πρόγραμμα περιήγησης εκτελεί στο παρασκήνιο, ξεχωριστά από την ιστοσελίδα, ανοίγοντας δυνατότητες μη διαθέσιμες σε συνηθισμένους ιστότοπους: αναχαίτιση αιτημάτων δικτύου, προσωρινή αποθήκευση πόρων, συγχρονισμός παρασκηνίου και ειδοποιήσεις push. Το manifest — είναι ένα αρχείο JSON που ενημερώνει το πρόγραμμα περιήγησης πώς πρέπει να φαίνεται η εφαρμογή κατά την εγκατάσταση στη συσκευή: όνομα, εικονίδια, χρώμα θέματος, προσανατολισμός οθόνης. Χωρίς HTTPS, το Service Worker δεν λειτουργεί — αυτή είναι υποχρεωτική απαίτηση ασφαλείας. Το PWA είναι συμβατό με οποιοδήποτε σύγχρονο πρόγραμμα περιήγησης και δεν απαιτεί δημοσίευση στο κατάστημα εφαρμογών. Ο χρήστης ανοίγει τον ιστότοπο, βλέπει την πρόταση εγκατάστασης της εφαρμογής, πατά «Προσθήκη στην αρχική οθόνη» — και η εφαρμογή είναι έτοιμη. Για τις επιχειρήσεις, το PWA σημαίνει κάλυψη οποιουδήποτε κοινού χωρίς κόστος ανάπτυξης ξεχωριστά για iOS και Android, υψηλή ταχύτητα φόρτωσης ακόμη και σε αργά δίκτυα και αφοσίωση μέσω ειδοποιήσεων push. Στο άρθρο θα αναλύσουμε πώς λειτουργεί το Service Worker, πώς να δημιουργήσετε manifest, ποιες στρατηγικές προσωρινής αποθήκευσης να χρησιμοποιήσετε και πώς να παρέχετε πρόσβαση εκτός σύνδεσης.
Κύρια σημεία
Κύρια σημεία
Progressive Web App (PWA) — είναι μια προσέγγιση ανάπτυξης διαδικτυακών εφαρμογών που συνδυάζει τις καλύτερες ιδιότητες του ιστού και των εγγενών εφαρμογών. Ο όρος εισήχθη από τον Francesco Berriman το 2015, και η Google προωθεί ενεργά το PWA ως αντικατάσταση των απλών εφαρμογών κινητού. Η βασική ιδέα: ο ιστότοπος βελτιώνεται σταδιακά ανάλογα με τις δυνατότητες του προγράμματος περιήγησης και της συσκευής. Εάν το πρόγραμμα περιήγησης υποστηρίζει Service Worker — ενεργοποιείται η λειτουργία εκτός σύνδεσης. Εάν υποστηρίζει manifest — εμφανίζεται το κουμπί «Εγκατάσταση». Εάν υπάρχει API ειδοποιήσεων — η εφαρμογή μπορεί να στέλνει push. Ο χρήστης σε αδύναμη συσκευή με αργό διαδίκτυο θα λάβει τη βασική έκδοση του ιστότοπου, ενώ σε ένα σύγχρονο smartphone — μια πλήρη εφαρμογή με εικονίδιο στην επιφάνεια εργασίας.
Το PWA δεν χρειάζεται να εγκατασταθεί μέσω καταστήματος εφαρμογών. Αρκεί ένας σύνδεσμος. Αυτό λύνει το κύριο πρόβλημα των εφαρμογών κινητού — το υψηλό εμπόδιο εισόδου. Ο χρήστης δεν πηγαίνει στο Google Play ή στο App Store, δεν περιμένει λήψη 100 MB, δεν δίνει δεκάδες άδειες. Απλώς ανοίγει τον ιστότοπο και το πρόγραμμα περιήγησης προτείνει την εγκατάσταση της εφαρμογής. Εάν ο χρήστης αρνηθεί — εξακολουθεί να χρησιμοποιεί τον ιστότοπο. Και αν συμφωνήσει — το εικονίδιο εμφανίζεται στην αρχική οθόνη και η εφαρμογή ανοίγει σαν εγγενής: χωρίς γραμμή διεύθυνσης προγράμματος περιήγησης, σε λειτουργία πλήρους οθόνης και με γρήγορη εκκίνηση.
Τεχνικά, το PWA πρέπει να πληροί τρία κριτήρια: να λειτουργεί μέσω HTTPS (ασφαλής σύνδεση), να έχει Service Worker (σενάριο επεξεργασίας παρασκηνίου) και να περιέχει manifest (Web App Manifest). Αυτά τα τρία συστατικά μετατρέπουν έναν συνηθισμένο ιστότοπο σε εγκαταστάσιμη εφαρμογή.
Service Worker — είναι ένα σενάριο JavaScript που το πρόγραμμα περιήγησης εκτελεί σε ξεχωριστό νήμα, ανεξάρτητα από την ιστοσελίδα. Δεν έχει πρόσβαση στο DOM, δεν μπορεί να αλληλεπιδράσει άμεσα με τη διεπαφή, αλλά μπορεί να αναχαιτίζει και να τροποποιεί αιτήματα δικτύου, να διαχειρίζεται την προσωρινή μνήμη, να επεξεργάζεται ειδοποιήσεις push και να εκτελεί συγχρονισμό παρασκηνίου. Το Service Worker λειτουργεί ως διακομιστής μεσολάβησης μεταξύ του προγράμματος περιήγησης και του δικτύου: κάθε αίτημα από τη σελίδα περνά μέσω του Service Worker, το οποίο αποφασίζει — να επιστρέψει δεδομένα από την προσωρινή μνήμη, να ζητήσει από τον διακομιστή ή να κάνει και τα δύο.
Το Service Worker ζει σύμφωνα με τον δικό του κύκλο ζωής, που δεν συνδέεται με την ανοιχτή σελίδα. Εγκαθίσταται, ενεργοποιείται και λειτουργεί στο παρασκήνιο ακόμη και μετά το κλείσιμο όλων των καρτελών του ιστότοπου. Αυτό επιτρέπει στο PWA να λαμβάνει ειδοποιήσεις push και να ενημερώνει την προσωρινή μνήμη στο παρασκήνιο, χωρίς τη συμμετοχή του χρήστη.
Το Service Worker περνά από τέσσερα στάδια: εγγραφή, εγκατάσταση, ενεργοποίηση και αδράνεια/τερματισμός.
Εγγραφή. Το πρόγραμμα περιήγησης λαμβάνει έναν σύνδεσμο προς το αρχείο JS του Service Worker και ξεκινά τη λήψη. Η εγγραφή εκτελείται από συνηθισμένο JavaScript στη σελίδα:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW καταχωρήθηκε:', registration.scope);
})
.catch(error => {
console.log('Η εγγραφή SW απέτυχε:', error);
});
}Εγκατάσταση. Μετά την επιτυχή λήψη, το πρόγραμμα περιήγησης ενεργοποιεί το συμβάν install. Σε αυτό το στάδιο, συνηθίζεται να αποθηκεύονται προσωρινά οι βασικοί πόροι (σκελετός HTML, CSS, κύριες εικόνες) ώστε η εφαρμογή να μπορεί να λειτουργεί εκτός σύνδεσης. Εάν η εγκατάσταση είναι επιτυχής, το Service Worker προχωρά στο επόμενο στάδιο. Εάν το σενάριο προκαλέσει σφάλμα — η εγκατάσταση ακυρώνεται και το παλιό Service Worker συνεχίζει να λειτουργεί.
self.addEventListener('install', event => {
event.waitUntil(
caches.open('pwa-cache-v1').then(cache => {
return cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js',
'/images/logo.png'
]);
})
);
});Ενεργοποίηση. Όταν όλες οι καρτέλες του ιστότοπου είναι κλειστές, το παλιό Service Worker τερματίζεται και το νέο ενεργοποιείται. Το συμβάν activate χρησιμοποιείται για τον καθαρισμό παλιών προσωρινών μνημών και μετεγκατάσταση δεδομένων:
self.addEventListener('activate', event => {
const cacheWhitelist = ['pwa-cache-v2'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});Αδράνεια. Το ενεργοποιημένο Service Worker αναχαιτίζει αιτήματα και επεξεργάζεται συμβάντα. Μπορεί να σταματήσει από το πρόγραμμα περιήγησης για εξοικονόμηση πόρων και να επανεκκινηθεί στο επόμενο αίτημα. Το Service Worker βασίζεται σε συμβάντα: ζει μόνο όσο επεξεργάζεται συμβάντα.
Το Service Worker υποστηρίζει αρκετές στρατηγικές προσωρινής αποθήκευσης. Η επιλογή εξαρτάται από τον τύπο του πόρου και τις απαιτήσεις επικαιρότητας των δεδομένων.
Cache First (πρώτα προσωρινή μνήμη). Πρώτα ελέγχεται η προσωρινή μνήμη. Εάν ο πόρος βρεθεί — επιστρέφεται από την προσωρινή μνήμη. Εάν όχι — το αίτημα πηγαίνει στον διακομιστή, η απάντηση αποθηκεύεται στην προσωρινή μνήμη. Η στρατηγική είναι κατάλληλη για στατικούς πόρους: εικόνες, γραμματοσειρές, CSS, JS. Παρέχει μέγιστη ταχύτητα και πλήρη λειτουργία εκτός σύνδεσης.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(fetchResponse => {
return caches.open('pwa-cache-v1').then(cache => {
cache.put(event.request, fetchResponse.clone());
return fetchResponse;
});
});
})
);
});Network First (πρώτα δίκτυο). Το αίτημα πηγαίνει πρώτα στον διακομιστή. Εάν ο διακομιστής απαντήσει — τα δεδομένα επιστρέφονται στον χρήστη και αποθηκεύονται στην προσωρινή μνήμη. Εάν ο διακομιστής δεν είναι διαθέσιμος — επιστρέφεται το αντίγραφο από την προσωρινή μνήμη. Η στρατηγική είναι κατάλληλη για αιτήματα API, ειδήσεις, περιεχόμενο που πρέπει να είναι επικαιροποιημένο αλλά μπορεί να λειτουργεί και εκτός σύνδεσης.
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request).then(response => {
return caches.open('pwa-dynamic-v1').then(cache => {
cache.put(event.request, response.clone());
return response;
});
}).catch(() => {
return caches.match(event.request);
})
);
});Stale While Revalidate (παλιό με ανανέωση). Η απάντηση επιστρέφεται αμέσως από την προσωρινή μνήμη, ενώ στο παρασκήνιο αποστέλλεται αίτημα στον διακομιστή για ενημέρωση της προσωρινής μνήμης. Ο χρήστης βλέπει το περιεχόμενο αμέσως και το επόμενο αίτημα θα λάβει ήδη φρέσκα δεδομένα. Ιδανικό για περιεχόμενο που αλλάζει, αλλά δεν είναι κρίσιμο εάν ο χρήστης δει μια έκδοση λίγα λεπτά παλαιότερη.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
const fetchPromise = fetch(event.request).then(response => {
return caches.open('pwa-dynamic-v1').then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
return cached || fetchPromise;
})
);
});Το manifest — είναι ένα αρχείο JSON, συνήθως manifest.json, το οποίο συνδέεται μέσω της ετικέτας <link> στο head της σελίδας HTML. Ενημερώνει το πρόγραμμα περιήγησης πώς πρέπει να εμφανίζεται η εφαρμογή κατά την εγκατάσταση στη συσκευή: όνομα, εικονίδια διαφορετικών μεγεθών, χρώμα φόντου, χρώμα θέματος, προσανατολισμός και λειτουργία εμφάνισης (πρόγραμμα περιήγησης, ελάχιστο UI, πλήρης οθόνη).
{
"name": "PWA Demo App",
"short_name": "PWA Demo",
"description": "Επίδειξη εφαρμογής PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3f51b5",
"orientation": "portrait",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}Η παράμετρος display καθορίζει πώς θα φαίνεται η εφαρμογή μετά την εγκατάσταση. Το standalone κρύβει τη γραμμή διεύθυνσης του προγράμματος περιήγησης και το πλαίσιο πλοήγησης — η εφαρμογή φαίνεται σαν εγγενής. Το fullscreen χρησιμοποιεί ολόκληρη την οθόνη χωρίς κανένα στοιχείο προγράμματος περιήγησης. Το minimal-ui αφήνει ελάχιστα στοιχεία προγράμματος περιήγησης (κουμπιά πίσω και ανανέωσης).
Τα εικονίδια πρέπει να προετοιμαστούν σε τουλάχιστον δύο μεγέθη: 192x192 και 512x512 pixel. Η μορφή PNG με υποστήριξη της παραμέτρου purpose (για παράδειγμα, maskable) επιτρέπει στο πρόγραμμα περιήγησης να προσαρμόσει το εικονίδιο στο σχήμα του περιβλήματος της συσκευής — στο Android το εικονίδιο μπορεί να κοπεί σε στρογγυλεμένο τετράγωνο. Μετά τη σύνδεση του manifest, το πρόγραμμα περιήγησης Chrome στο Android αρχίζει να εμφανίζει το banner «Προσθήκη στην αρχική οθόνη» όταν πληρούνται οι προϋποθέσεις: HTTPS, καταχωρημένο Service Worker, σωστό manifest και τουλάχιστον δύο επισκέψεις με διάστημα 5 λεπτών.
Το PWA μπορεί να στέλνει ειδοποιήσεις push σαν εγγενής εφαρμογή. Για αυτό χρησιμοποιούνται δύο API: Push API (αποστολή από διακομιστή) και Notification API (εμφάνιση στη συσκευή). Το Service Worker λαμβάνει το συμβάν push ακόμη και αν η εφαρμογή δεν είναι ανοιχτή και μπορεί να εμφανίσει μια ειδοποίηση με τίτλο, κείμενο και εικονίδιο.
Για τη λήψη ειδοποιήσεων push, ο χρήστης πρέπει να δώσει άδεια:
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('Push επιτρέπεται');
}
});Το Service Worker εγγράφεται στο συμβάν push και εμφανίζει την ειδοποίηση:
self.addEventListener('push', event => {
const data = event.data.json();
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192x192.png',
badge: '/icons/badge-72x72.png',
actions: [
{ action: 'open', title: 'Άνοιγμα' },
{ action: 'close', title: 'Κλείσιμο' }
]
});
});
self.addEventListener('notificationclick', event => {
event.notification.close();
if (event.action === 'open') {
clients.openWindow('/');
}
});Για την αποστολή push από τον διακομιστή χρησιμοποιείται το πρωτόκολλο Web Push (VAPID). Ο διακομιστής κρυπτογραφεί το μήνυμα και το στέλνει μέσω της υπηρεσίας push του προγράμματος περιήγησης (Firebase Cloud Messaging για Chrome, Mozilla Autopush για Firefox). Η συνδρομή του χρήστη (αντικείμενο PushSubscription) πρέπει να αποθηκεύεται στον διακομιστή κατά την εγγραφή.
Το PWA πρέπει να είναι γρήγορο. Το Google Lighthouse — είναι ένα εργαλείο ελέγχου που εξετάζει το PWA σύμφωνα με μια λίστα ελέγχου: εγγραφή Service Worker, απόκριση 200 σε πρόσβαση εκτός σύνδεσης, σωστό manifest, HTTPS, σωστό μέγεθος εικονιδίων, γρήγορη φόρτωση σε αργά δίκτυα. Ελάχιστη βαθμολογία επιτυχίας για PWA — 80 στα 100 στην κλίμακα Lighthouse. Οι εφαρμογές με βαθμολογία κάτω από 80 δεν λαμβάνουν banner εγκατάστασης στο Chrome.
Βασικές μετρήσεις απόδοσης για PWA — First Contentful Paint (FCP) έως 1,8 δευτερόλεπτα, Largest Contentful Paint (LCP) έως 2,5 δευτερόλεπτα, Time to Interactive (TTI) έως 3,5 δευτερόλεπτα. Το Service Worker μπορεί να βελτιώσει σημαντικά το FCP και LCP εάν αποθηκεύει προσωρινά το κρίσιμο HTML και CSS κατά την εγκατάσταση. Η στρατηγική Cache First για στατικό περιεχόμενο και Stale While Revalidate για API παρέχει την καλύτερη εμπειρία χρήστη.
Μία από τις κύριες δυνατότητες του PWA — λειτουργία χωρίς διαδίκτυο. Το Service Worker αναχαιτίζει αιτήματα και επιστρέφει προσωρινά αποθηκευμένες εκδόσεις σελίδων. Εάν ο χρήστης προσπαθήσει να ανοίξει μια σελίδα που δεν υπάρχει στην προσωρινή μνήμη, μπορεί να εμφανιστεί μια προσαρμοσμένη σελίδα εφεδρείας:
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
}).catch(() => {
return caches.match('/offline.html');
})
);
});Ο συγχρονισμός παρασκηνίου (Background Sync) επιτρέπει την αναβολή της αποστολής δεδομένων στον διακομιστή εάν η συσκευή είναι εκτός σύνδεσης. Το Service Worker αποθηκεύει το αίτημα και το στέλνει αυτόματα όταν αποκατασταθεί η σύνδεση:
self.addEventListener('sync', event => {
if (event.tag === 'sync-messages') {
event.waitUntil(sendMessages());
}
});
function sendMessages() {
return caches.open('pwa-pending-v1').then(cache => {
return cache.keys().then(requests => {
return Promise.all(requests.map(request => {
return fetch(request).then(() => cache.delete(request));
}));
});
});
}Το Chrome DevTools παρέχει τον πίνακα Application, όπου μπορείτε να κάνετε εντοπισμό σφαλμάτων Service Worker (εγγραφή, κατάσταση, προσωρινή μνήμη, push), να ελέγχετε το manifest, να καθαρίζετε την προσωρινή μνήμη και να δημιουργείτε δικές σας ειδοποιήσεις push για δοκιμή. Η καρτέλα Network με εξομοίωση λειτουργίας εκτός σύνδεσης βοηθά στον έλεγχο της λειτουργίας της προσωρινής μνήμης. Το Lighthouse στον πίνακα Audits παρέχει πλήρη έλεγχο PWA με συστάσεις.
Workbox — βιβλιοθήκη από την Google που απλοποιεί τη δημιουργία Service Worker. Αντί για χειροκίνητη σύνταξη στρατηγικών προσωρινής αποθήκευσης, το Workbox προσφέρει έτοιμες μονάδες:
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
/\.(?:png|jpg|jpeg|svg|gif)$/,
new StaleWhileRevalidate()
);Το Workbox ενσωματώνεται με συσκευαστές (Webpack, Vite) και δημιουργεί αυτόματα το προσωρινό manifest. Το PWA Builder (pwabuilder.com) από τη Microsoft δημιουργεί όλα τα αρχεία PWA online: Service Worker, manifest, εικονίδια, πρότυπο HTML.
Συχνές Ερωτήσεις
PWA — είναι ένας ιστότοπος που μετά την εγκατάσταση στο τηλέφωνο λειτουργεί σαν συνηθισμένη εφαρμογή: εικονίδιο στην επιφάνεια εργασίας, πρόσβαση εκτός σύνδεσης, ειδοποιήσεις push, λειτουργία πλήρους οθόνης χωρίς γραμμή διεύθυνσης προγράμματος περιήγησης. Δεν χρειάζεται να πάτε στο App Store ή στο Google Play — η εγκατάσταση γίνεται με ένα κλικ από το πρόγραμμα περιήγησης.
Η εγγενής εφαρμογή γράφεται για μια συγκεκριμένη πλατφόρμα (Swift για iOS, Kotlin για Android), απαιτεί δημοσίευση στο κατάστημα και χειροκίνητη εγκατάσταση. Το PWA — είναι ένας ιστότοπος γραμμένος σε HTML, CSS και JavaScript, που μπορεί να εγκατασταθεί στη συσκευή μέσω προγράμματος περιήγησης. Το PWA δεν καταλαμβάνει πολύ χώρο (μόνο προσωρινή μνήμη), ενημερώνεται αυτόματα και υποστηρίζεται από όλα τα σύγχρονα προγράμματα περιήγησης.
Chrome, Firefox, Safari (από iOS 11.3), Edge, Samsung Internet, Opera. Το Service Worker υποστηρίζεται από όλα τα σύγχρονα προγράμματα περιήγησης, εκτός από το Internet Explorer. Το Safari έχει περιορισμένη υποστήριξη για ειδοποιήσεις push, αλλά οι βασικές δυνατότητες PWA (εγκατάσταση στην αρχική οθόνη, πρόσβαση εκτός σύνδεσης) λειτουργούν.
Ναι. Για αυτό πρέπει να προστεθεί manifest (manifest.json), να δημιουργηθεί και να καταχωρηθεί Service Worker (sw.js), να μεταφερθεί ο ιστότοπος σε HTTPS, να προστεθούν μετα-ετικέτες και εικονίδια. Ο ίδιος ο ιστότοπος δεν απαιτεί επανεγγραφή εάν λειτουργεί σε JavaScript και επιστρέφει HTML. Εάν ο ιστότοπος είναι πλήρως διακομιστής (MPA), το Service Worker μπορεί να προστεθεί ως επίπεδο προσωρινής αποθήκευσης χωρίς αλλαγή της αρχιτεκτονικής.
Όταν ο χρήστης ανοίγει το PWA, το πρόγραμμα περιήγησης ελέγχει εάν το αρχείο Service Worker στον διακομιστή έχει αλλάξει. Εάν το αρχείο διαφέρει τουλάχιστον κατά ένα byte, το πρόγραμμα περιήγησης κατεβάζει το νέο Service Worker και ξεκινά την εγκατάστασή του. Το παλιό Service Worker συνεχίζει να λειτουργεί έως ότου κλείσουν όλες οι καρτέλες της εφαρμογής. Μετά το κλείσιμο των καρτελών, το νέο Service Worker ενεργοποιείται και αντικαθιστά το παλιό. Ο χρήστης μπορεί να αναγκάσει την ενημέρωση της εφαρμογής επαναφορτώνοντας τη σελίδα.
Το PWA είναι δικαιολογημένο εάν ο στόχος είναι η κάλυψη του μέγιστου κοινού χωρίς κόστος ανάπτυξης για δύο πλατφόρμες, εάν η εφαρμογή δεν απαιτεί βαθιά πρόσβαση στο υλικό (Bluetooth, NFC, κάμερα στο παρασκήνιο), εάν το περιεχόμενο αλλάζει συχνά. Για σύνθετες εφαρμογές (παιχνίδια, επεξεργαστές βίντεο) η εγγενής εφαρμογή παραμένει προτιμότερη. Το PWA χρησιμοποιείται συχνά ως πρόσθετο κανάλι ή ως MVP πριν από την πλήρη εφαρμογή.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης