What's inside
ShopKit is the source code of a shopping app for iOS and Android, written in Flutter, plus a free WordPress plugin that connects it to a WooCommerce store. Every app runs in two modes:
- Demo mode (the default): the app runs on a sample store bundled inside it. No server, no account, no internet connection needed. Use it to look around and to choose a design.
- Live mode: start the app with your store's connection code and every screen shows your WooCommerce products, prices, cart, customers and orders.
The folders in your download
| Folder or file | What it is |
|---|---|
README.txt | A one-page quick start in plain text. |
documentation/ | This guide. Open documentation/index.html in a browser. |
shopkit/templates/ | The 11 apps. Each folder is a complete Flutter app you can open, run and publish on its own. |
shopkit/packages/ | Code the apps share: shopkit_core (screens, widgets, themes, fonts, translations),
shopkit_domain (data models and interfaces), shopkit_data_mock (the sample store and its photos),
shopkit_data_woo (the WooCommerce connection), shopkit_app (connecting a store in the app,
optional push). |
plugin/webkoding-shopkit-connect.zip | The Webkoding ShopKit Connect for WooCommerce plugin, ready to upload to WordPress. |
shopkit/backends/wordpress/ | The same plugin as readable source, with the API contract (API.md). You do not need this folder to use the plugin. |
shopkit/tools/ | extract_template.sh (copy one app out as a standalone project), apply_app_icon.sh (generate every icon size). |
design-source/ | The original screen designs as web pages and the 1024 × 1024 app icon. See Design files. |
Changelog.txt, LICENSE.txt | Version history and licence. |
Screens per app (counted from the source files)
| App folder | Design | Own screens | Screen codes |
|---|---|---|---|
core_kit | Core Kit (general store, light + dark) | 48 | S01-S48 |
electro | Electro (electronics) | 17 | E01-E17 |
aura | Aura (jewellery, luxury) | 16 | A01-A16 |
pawly | Pawly (pet supplies) | 16 | P01-P16 |
fresho | Fresho (grocery delivery) | 15 | F01-F15 |
fold | Fold (editorial fashion) | 16 | FL01-FL16 |
glow | Glow (beauty, skincare) | 16 | G01-G16 |
nest | Nest (furniture, home) | 16 | N01-N16 |
peak | Peak (sport, fitness) | 15 | K01-K15 |
tods | Tods (toys, kids, gifts) | 17 | T01-T17 |
showcase | A gallery app that opens every screen above on its sample store | all | - |
Each niche app also uses the shared Core Kit screens it needs (password reset, addresses, orders, settings, reviews, filters...) drawn in its own colours and fonts, so every app is a complete shop.
Requirements
| For | You need | Where the number comes from |
|---|---|---|
| Running the apps | Flutter 3.24 or newer (Dart 3.3 or newer). Built and tested with Flutter 3.44.7 / Dart 3.12.2. | environment: in every pubspec.yaml |
| Android | Android 7.0 or newer on the phone (minSdk = 24); Android Studio or the Android SDK with API 36 and Java 17 to build. | android/app/build.gradle.kts: minSdk = 24, compileSdk = 36, targetSdk = 36 |
| iOS | iOS 15.0 or newer on the phone; a Mac with Xcode to build (tested with Xcode 27.0). | IPHONEOS_DEPLOYMENT_TARGET = 15.0 |
| Your store (live mode only) | WordPress 6.5+, PHP 7.4+, WooCommerce 10.0+, HTTPS. Tested up to WordPress 7.1 and WooCommerce 11.1. | Plugin header and readme.txt |
Demo mode needs none of the store requirements and no paid account of any kind.
Prerequisites start here if you are new
ShopKit is source code, so you build it with the standard Flutter tools. If you have used a terminal before, skip to Run in demo mode. If not, this section covers what you need. It takes about fifteen minutes.
What to install
| Tool | Why |
|---|---|
| Flutter SDK (includes Dart) | Builds and runs the app. Follow the official installer for your operating system. |
| VS Code with the Flutter extension, or Android Studio | Your editor. One of them is enough. |
| Android Studio / Android SDK | To build for Android and run an Android emulator. |
| Xcode (Mac only) | To build for iPhone. iOS apps cannot be built on Windows or Linux. |
Opening a terminal
- macOS: press
Cmd+Space, type Terminal, press Enter. - Windows: press the Start key, type PowerShell, press Enter.
- Linux: press
Ctrl+Alt+T. - In your editor: VS Code has Terminal → New Terminal; it opens in your project folder.
The four commands you need
| Command | What it does |
|---|---|
pwd (Windows: cd alone) | Shows the folder you are in. |
ls (Windows: dir) | Lists files. Inside an app folder you see pubspec.yaml and lib. |
cd <folder> | Moves into a folder. cd .. goes up one level. |
clear (Windows: cls) | Clears the screen. |
Tip: type cd with a space, drag a folder from Finder or File Explorer onto the terminal and
press Enter; the path is filled in for you. Tab completes a folder name, ↑ repeats the last command.
Check Flutter
flutter --version
flutter doctor
flutter doctor lists your setup with a tick or a cross per item. Fix the crosses for the platforms you
want (a cross next to Xcode does not matter if you only build for Android).
"flutter: command not found" means Flutter is installed but not on your
PATH. Redo the "Update your path" step of the install
guide, then close and reopen the terminal.
Unzip to a simple path
Extract the download to a folder whose path has no spaces and no non-English characters, for example
~/dev/shopkit or C:\dev\shopkit. Some build tools still trip over unusual paths.
Somewhere to run the app
A phone with USB debugging on, an Android emulator (Android Studio → Device Manager) or the iOS Simulator
(Xcode → Open Developer Tool → Simulator). Check what Flutter sees with flutter devices.
Run in demo mode
Every app opens on its bundled sample store when you start it without a connection code. Everything is inside the app: products, photos (license-safe, bundled), fonts and translations, so it works offline.
cd shopkit/templates/core_kit
flutter pub get
flutter run
Replace core_kit with any other app folder: electro, aura, pawly,
fresho, fold, glow, nest, peak, tods, or
showcase to browse every design in one app.
The android/ and ios/ folders are included in every app, so you do not need
flutter create .. You only run it if you want to add another platform yourself.
What demo mode simulates: sign-in accepts the sample account, card payments are simulated, the push switch uses a demo token, and screens that need services WooCommerce does not have (courier map, chat, loyalty points, saved cards...) show sample content. In live mode those screens are hidden. See Choosing a template.
Video: "Live in 10 minutes" setup video (63 seconds, no
sound, English captions), included at documentation/video/setup-walkthrough.mp4 and recorded with
version 2.0. It follows Live in 10 minutes on a real local WooCommerce store: upload and
activate the ShopKit Connect plugin, the Status tab, create an app key (QR code and connection JSON), open the Core
Kit app, connect it under Settings → Store by pasting the JSON (the simulator has no camera; on a phone you
scan the QR code), add a product variation to the cart, check out with cash on delivery, and see the order in
WooCommerce → Orders. Waiting parts are sped up; the key's secret is blurred.
Live in 10 minutes connect your WooCommerce store
You need a WordPress site with WooCommerce on HTTPS and a WordPress administrator account. The plugin does not change your shop's pages; it only adds what the app needs.
- Install the plugin
In WordPress go to Plugins → Add New → Upload Plugin, choose
plugin/webkoding-shopkit-connect.zipfrom your download, click Install Now, then Activate. - Check the Status tab
Open WooCommerce → ShopKit Connect. The Status tab checks nine things: WooCommerce,
permalinks, HTTPS, the checkout page, app keys, background jobs, push, customer registration and whether the site can
reach its own Store API. Fix anything marked red before you continue.

Status tab on a test store - Create an app key
On the App keys tab, give the key a name (for example "iOS app") and click Create key. The page shows a
connection JSON and a QR code of the same JSON. Copy the JSON now: it is shown only
once. If you lose it, create a new key and revoke the old one.
It looks like this (the key below is an example, not a working key):
The app key identifies your app build; it is not a password and it never gives access to your WooCommerce REST API. Customer data still needs the customer's own sign-in.{"type":"shopkit-connect","version":1, "site_url":"https://store.example/", "api_url":"https://store.example/wp-json/", "app_key":"ak_0123456789abcdef.AbCdEfGhIjKlMnOp"}
App keys tab right after creating a key (a throw-away key on a local test site). - Give the code to the app
There are two ways. Use the first to try your store, the second for the app you publish.
In the app: scan or paste (no rebuild)
Run the app as it comes (
flutter run, demo mode) and open Connect your store: on the Profile tab while signed out, or Profile → Settings → Store while signed in. Tap Scan QR code and point the camera at the QR code on the plugin page, or paste the connection JSON and tap Connect. The app checks the code (it must be a ShopKit Connect code with anhttps://address; plainhttp://is accepted only for a local test store in a debug build), asks your store whether the key is valid, keeps the code in the phone's secure storage (Keychain / Keystore) and restarts on your store. It stays connected after the app is closed. Disconnect and use the demo store on the same screen signs out, forgets the code and everything kept for that store, and goes back to the demo store.The camera is used only for this scan; the permission text is in English, Arabic and Turkish (
ios/Runner/*.lproj/InfoPlist.strings; Android shows its own system text). Web builds have no scan button: paste the JSON instead.At build time (the app you publish)
Pass the same JSON with a
--dart-define. The store is then fixed, the app never reads a saved code, and Connect your store is hidden everywhere, so your customers never see it. In the app folder you chose:cd shopkit/templates/fresho flutter run --dart-define=SHOPKIT_CONNECTION='{"type":"shopkit-connect","version":1,"site_url":"https://store.example/","api_url":"https://store.example/wp-json/","app_key":"ak_..."}'Windows PowerShell and some shells mangle the quotes in JSON. If that happens, pass the base64 of the JSON instead; the app accepts both. macOS / Linux:
printf '%s' '<the JSON>' | base64. PowerShell:[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('<the JSON>')). Thenflutter run --dart-define=SHOPKIT_CONNECTION=<the base64 text>.To avoid typing it every time, put it in a file and use
--dart-define-from-file: createconnection.jsonnext topubspec.yamlwith{"SHOPKIT_CONNECTION": "<the base64 text>"}and runflutter run --dart-define-from-file=connection.json. Keep this file out of public repositories.A build that should only ever show the demo store (for example a public demo) can hide the in-app flow with
--dart-define=SHOPKIT_HIDE_CONNECT=true. - Run it The app opens on your store. Sign in with a customer account (store staff accounts are refused on purpose, see Troubleshooting), add a product to the cart and check out. Cash on delivery and bank transfer finish inside the app; card gateways open your own checkout page inside the app.
Optional: what you can set in the plugin
| Tab | Setting | Used by the app? |
|---|---|---|
| App settings | Feature switches: wishlist, notification feed, push, registration, checkout on your checkout page, writing reviews, deleting the account | Yes. A feature switched off is hidden in the app. |
| App settings | Logo, home screen banners, contact email, phone and address, support, terms and refund links, free-shipping threshold | Yes. The store name and logo appear on the splash screen of every app (the logo replaces the design's own mark) and the store name in the settings footer and the app switcher title. |
| App settings | Primary colour | Core Kit only: used as its accent colour (buttons, links, selected states). The niche apps keep their own curated palette and ignore it. A colour too light for white text is ignored. To recolour a niche app, see Branding. |
| Push | Log only or Firebase Cloud Messaging; which order statuses notify; test message; broadcast | See Push notifications |
| Logs | Plugin log (no personal data) | For you |


Choosing a template
Pick the design closest to your shop; the data, cart, checkout and account behaviour are the same in all of them.
Run any of them in demo mode first, or run showcase to flip through all designs.
| App | Best for | Fonts (bundled) | Demo-only parts, hidden in live mode |
|---|---|---|---|
| Core Kit | Any general store; light and dark | Plus Jakarta Sans | OTP code sign-in, saved cards, courier card, support chat, map strip, returns, seller store, loyalty points, help centre FAQ, currency switch |
| Electro | Electronics, gadgets | Space Grotesk | Live courier card and map, store credit, member level, warranties, price alerts, back-in-stock "Notify", trending searches |
| Aura | Jewellery, luxury fashion | Jost, Cormorant Garamond | Atelier progress, concierge, store credit, saved sizes, member events, trust badges |
| Pawly | Pet supplies | Nunito | Pet profiles, subscriptions list, Paw Points, courier card |
| Fresho | Grocery delivery | Manrope | "15 min" promise, rider map and card, Fresh Club, substitution approvals, OTP sign-in. Delivery slots are your shipping methods. |
| Fold | Editorial fashion | Archivo, Playfair Display | Lookbook, saved sizes, store credit, members preview, drop and back-in-size alerts, trending searches |
| Glow | Beauty, skincare | Lora, Karla | Ritual tracker, streaks, skin profile and quiz, fragrance-note chart, free samples, gift wrap, glow points |
| Nest | Furniture, home | DM Serif Display, Work Sans | "View in your room" card (a static layout, no AR), delivery windows, assembly, room plans, warranties |
| Peak | Sport, fitness (dark) | Barlow, Barlow Condensed | Training programme, store credit, training goal, trending searches, price alerts, free-gift threshold |
| Tods | Toys, kids, gifts | Baloo 2 | Child profiles, gift box builder, gift wrap, wish-jar sharing, trending searches. Age chips use your store's "Age" attribute. |
"Hidden in live mode" means WooCommerce has no data for it, so the app does not show sample content to your customers.
Each app's README.md lists the same.
Using one app on its own
The apps use the shared packages through relative paths, so keep the folder layout, or copy one app out as a self-contained project:
cd shopkit/tools
./extract_template.sh fresho ~/dev/my-grocery-app
Screen gallery
Captured from the apps themselves running on their sample stores (37 of the 192 screens; the showcase app opens every one). Click a picture to enlarge it.
Core Kit general store, light + dark











Electro electronics




Aura jewellery, luxury




Fresho grocery delivery



Fold editorial fashion




Glow beauty, skincare



Nest furniture, home




Peak sport, fitness




Pawly and Tods use emoji in their designs, which this capture method cannot draw, so they are not pictured here. Run shopkit/templates/showcase to see every screen of every design, including these two.
Branding Guide do this before you publish
You change values, not logic. After saving a Dart file, press r in the terminal running
flutter run to reload; for icons, names and package ids stop the app and run it again.
1. Package name and bundle id (required)
Every app ships with our ids (com.webkoding.<app>). You must replace
them with your own reverse-domain id, for example com.yourshop.app. Google Play and the App Store
reject an id that is already taken, an id cannot be changed after the first upload, and com.example is refused
by both stores.
| Platform | File | Change |
|---|---|---|
| Android | android/app/build.gradle.kts | applicationId = "com.webkoding.fresho" → your id. This is the id Google Play uses.
Changing namespace as well is optional; if you do, move android/app/src/main/kotlin/com/webkoding/<app>/MainActivity.kt
to the matching folders and update its package line. |
| iOS | ios/Runner.xcodeproj/project.pbxproj | Open ios/Runner.xcworkspace in Xcode → Runner target →
Signing & Capabilities → Bundle Identifier. Or replace every PRODUCT_BUNDLE_IDENTIFIER = com.webkoding.fresho in the file
(three for the app, three for RunnerTests). |
2. App name
| Where it shows | File | Change |
|---|---|---|
| Under the icon on Android | android/app/src/main/AndroidManifest.xml | android:label="Fresho" |
| Under the icon on iOS | ios/Runner/Info.plist | CFBundleDisplayName and CFBundleName |
| Task switcher | lib/app.dart | title: 'Fresho' |
| Store name inside the app (live mode) | WordPress → Settings → General → Site Title | The app reads it from your store |
3. Icon
Replace design-source/assets/app-icon.png (1024 × 1024 PNG) with your own square icon, then generate every
Android and iOS size:
cd shopkit/tools
./apply_app_icon.sh fresho
The script copies the PNG into the app and runs flutter_launcher_icons. The PNG opens in any image editor.
4. Logo and splash
In live mode every app's splash screen shows the logo you set in the plugin (App settings → Logo, or the
site logo of your WordPress theme) in place of the design's own mark, with your store name. The onboarding
screens use the images in shopkit/packages/shopkit_core/assets/images/ (Fresho, Glow and Nest also have
their own assets/images/ folder); replace the files and keep the names.
5. Colours
Colours live in two places, both plain lists of Color(0xFFRRGGBB) values (0xFF means "opaque",
the last six characters are an ordinary hex colour):
| What | File |
|---|---|
| Core Kit (light) | shopkit/packages/shopkit_core/lib/theme/themes/core_theme.dart, dark: core_dark_theme.dart |
| Shared screens drawn in a niche theme (orders, addresses, settings...) | shopkit/packages/shopkit_core/lib/theme/themes/all_themes.dart, one class per theme |
| A niche app's own screens | shopkit/templates/<app>/lib/widgets/<app>_design.dart |
// core_theme.dart
accent: Color(0xFF4353E6), // your brand colour: buttons, links, active tabs
accentTonal: Color(0xFFEDEFFD), // a light tint of the accent: chips, badges
background: Color(0xFFFBFBFD),
surface: Color(0xFFFFFFFF),
text: Color(0xFF16161D),
Core Kit can also take its accent from the plugin: set App settings → Primary colour and the live app uses it for buttons, links and selected states (the rest of the palette stays). The niche apps do not: their palettes are designed as a whole, so change them in code.
For a niche app, change accent in both its *_design.dart file and its class in
all_themes.dart. Default accents:
| Theme | Accent | Theme | Accent |
|---|---|---|---|
| Core Kit | 0xFF4353E6 | Fold | 0xFF111111 |
| Electro | 0xFF22D3EE | Glow | 0xFFC25B6B |
| Aura | 0xFFA5842E | Nest | 0xFFB4643C |
| Pawly | 0xFFE8701B | Peak | 0xFFC8F131 |
| Fresho | 0xFF3E9B4F | Tods | 0xFF4E9BF5 (plus several accents) |
6. Fonts
The 15 font families are bundled as .ttf files (SIL Open Font License) in
shopkit/packages/shopkit_core/lib/assets/fonts/; nothing is downloaded at run time. Each app lists the families
it uses under fonts: in its pubspec.yaml. To use another font:
- Put its
.ttffiles in the app, for exampleassets/fonts/Inter/. - Add it under
flutter: fonts:in the app'spubspec.yamlwithfamily: Inter. - In the theme file, replace the
SkFonts.plusJakartaSans(call withSkFonts.style('Inter',, keeping the arguments.
7. Product photos and sample content
In live mode every product photo, name and price comes from your WooCommerce store. The sample store's photos
(shopkit/packages/shopkit_data_mock/assets/images/, credits in CREDITS.md next to them) are only
used in demo mode and are licensed CC0 or generated; you may keep or replace them.
8. Link scheme (optional)
Sign-in links and the return from checkout use the shopkit:// scheme. Keep it unless two of your apps are on
the same phone. To change it, edit the same word in four places: android/app/src/main/AndroidManifest.xml
(android:scheme), ios/Runner/Info.plist (CFBundleURLSchemes), lib/router.dart
(uri.scheme == 'shopkit') and the plugin's Deep link scheme setting.
Languages
Every app and the plugin come in English, Arabic and Turkish. Arabic is fully right to left. The app follows the phone's language and the customer can change it on the language screen; the choice is saved on the device. In live mode the app sends its language to your store, and the plugin answers its messages in that language.
Where the words live
| Words | Files | Keys per language |
|---|---|---|
| Shared screens and widgets (all Core Kit screens, cart, checkout, orders, errors...) | shopkit/packages/shopkit_core/lib/l10n/shopkit_en.arb, _ar.arb, _tr.arb | 482 |
| Aura screens | shopkit/templates/aura/lib/l10n/aura_en.arb, _ar, _tr | 101 |
| Electro screens | shopkit/templates/electro/lib/l10n/electro_en.arb, _ar, _tr | 87 |
| Fold screens | shopkit/templates/fold/lib/l10n/fold_en.arb, _ar, _tr | 78 |
| Fresho screens | shopkit/templates/fresho/lib/l10n/fresho_en.arb, _ar, _tr | 85 |
| Glow screens | shopkit/templates/glow/lib/l10n/glow_en.arb, _ar, _tr | 94 |
| Nest screens | shopkit/templates/nest/lib/l10n/nest_en.arb, _ar, _tr | 77 |
| Pawly screens | shopkit/templates/pawly/lib/l10n/pawly_en.arb, _ar, _tr | 81 |
| Peak screens | shopkit/templates/peak/lib/l10n/peak_en.arb, _ar, _tr | 68 |
| Showcase screens | shopkit/templates/showcase/lib/l10n/showcase_en.arb, _ar, _tr | 79 |
| Tods screens | shopkit/templates/tods/lib/l10n/tods_en.arb, _ar, _tr | 114 |
| The plugin (admin pages and messages to the app) | webkoding-shopkit-connect/languages/*.po | 224 |
Product names, descriptions, categories and reviews come from WooCommerce in your store's language and are not translated
by the app. Prices use your store's currency and the app language's number format ($1,299.00 in English,
$1.299,00 in Turkish).
Change a word
Edit the value in the .arb file, then regenerate the code in that folder:
cd shopkit/packages/shopkit_core # or shopkit/templates/<app>
flutter gen-l10n
Add a language (example: French)
- Copy
shopkit/packages/shopkit_core/lib/l10n/shopkit_en.arbtoshopkit_fr.arb, set"@@locale": "fr"and translate every value. Keep{placeholders}and plural forms as they are; you can drop the"@key"description entries. - Optional: add
"languageFrench": "Français"to everyshopkit_*.arbfile and a'fr' => t.languageFrenchline inSkLocale.nativeName(shopkit_core/lib/l10n/sk_l10n.dart); otherwise the language screen shows the code "fr". - Do the same for the app's own file, for example
shopkit/templates/fresho/lib/l10n/fresho_en.arb→fresho_fr.arb. - Run
flutter gen-l10ninshopkit_coreand in the app. French now appears on the language screen. - Run
flutter testinshopkit_core: the completeness test names any key you missed. - Plugin: add
webkoding-shopkit-connect-fr_FR.poand.moto the plugin'slanguages/folder (start from the.potfile there, with Poedit or any PO editor).
Tests that guard the translations
l10n_gate_test.dart: no hard-coded English text in screens and widgets.l10n_completeness_test.dart: every English key exists in every language with the same placeholders.l10n_rtl_test.dart: every screen painted in Arabic and Turkish on a small phone (320 points wide) with large text (1.3×) without a layout error.
Payments
| Payment method in WooCommerce | What happens in the app |
|---|---|
Cash on delivery (cod), direct bank transfer (bacs), cheque (cheque) | Chosen and placed inside the app through the WooCommerce Store API. The order success screen shows next. |
| Every other gateway (Stripe, PayPal, Square, iyzico, Apple Pay / Google Pay through your gateway...) | The app hands its cart to your own checkout page, opened in a secure in-app web view. The customer pays there exactly as on your website; then the app shows its order success screen. |
The app never sees card numbers and needs no gateway code: any gateway that works on your WooCommerce checkout works in the app. Only methods enabled in WooCommerce → Settings → Payments are offered.
- The hand-off link works once, expires after 5 minutes, and only opens from the app that created it.
- The Checkout on your store's checkout page switch in the plugin turns the web view path off. Then only the offline methods above are offered.
- Gateway fees are charged by the payment provider, not by ShopKit.
In demo mode card payment is simulated and no money moves.
Push notifications
The plugin sends a push message when an order changes status (by default: processing, on hold, completed, cancelled, refunded, failed), when you send a broadcast and when you send a test. Messages go out in the background through WooCommerce's Action Scheduler, so checkout never waits for them. Every message is also stored in the customer's in-app notification feed, which works without push.
Store side: the plugin
- Create a free project in the Firebase console.
- Project settings → Service accounts → Generate new private key. A
.jsonfile downloads. - Upload it to your server outside the web root (for example one folder above
public_html) so nobody can download it. - In WooCommerce → ShopKit Connect → Push choose Firebase Cloud Messaging and enter the absolute path of that file. The Status tab confirms the project id.
Until then the default Log only driver writes each notification to the plugin log and sends nothing anywhere.
App side: add your Firebase project
Every app already includes firebase_core and firebase_messaging, but not a Firebase project:
the project files (google-services.json, GoogleService-Info.plist) are yours and cannot ship in
a template. Without them the app runs normally with push switched off: no crash, no error messages, and
the push switch on the settings screen is hidden. The in-app notification feed works either way.
- Install the FlutterFire command line tool and connect the app to your Firebase project. It writes the platform files
and
lib/firebase_options.dart:dart pub global activate flutterfire_cli cd shopkit/templates/fresho flutterfire configure - Android and iOS read the platform files on their own; nothing else is needed. If you prefer the generated
options file (required for web), pass it in
lib/main.dart:import 'firebase_options.dart'; ... final push = await FirebasePushMessaging.start(options: DefaultFirebaseOptions.currentPlatform); - iOS only: in the Apple Developer account create an APNs key and upload it in Firebase → Project settings → Cloud Messaging; in Xcode add the Push Notifications and Background Modes → Remote notifications capabilities. The iOS simulator has no push token: test on a phone.
What the app then does, connected to your store with push switched on in the plugin:
- On first start it asks the customer for permission (iOS, Android 13 and later) and registers the phone with your
store (
POST shopkit/v1/devices). Before sign-in the phone gets broadcasts; after sign-in it is registered again so it also gets that customer's order updates. - When Firebase replaces the token, the new one is registered and the old one removed.
- On sign-out the phone is unregistered (
shopkit/v1/devices/unregister) and registered again for broadcasts only. Disconnecting from the store unregisters it. - Tapping an order-status notification opens that order.
- The settings switch turns push off and on for this phone.
Switching Push notifications off in the plugin hides the switch and stops the registration. Web builds do not use push unless you pass the Firebase options and add Firebase's web service worker yourself.
Send a test from the plugin's Push tab with a device token from the plugin log.
Costs: sending messages with Firebase Cloud Messaging is free of charge at the time of writing; check Google's current pricing. iOS push needs the paid Apple Developer Program.
Building for Release
Before your first release: replace the package name and bundle id, the app name and the icon
(Branding Guide), and build with your connection code. A build without
SHOPKIT_CONNECTION is the demo app.
Android: APK and App Bundle
The release build is signed with the debug key so that flutter run --release works out of
the box. Google Play does not accept that. Create your own upload key once and keep it safe:
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
Create android/key.properties (do not share it):
storePassword=...
keyPassword=...
keyAlias=upload
storeFile=/Users/you/upload-keystore.jks
In android/app/build.gradle.kts, add at the top and replace the release block:
import java.util.Properties
import java.io.FileInputStream
val keyProps = Properties().apply {
val f = rootProject.file("key.properties")
if (f.exists()) load(FileInputStream(f))
}
android {
...
signingConfigs {
create("release") {
keyAlias = keyProps["keyAlias"] as String?
keyPassword = keyProps["keyPassword"] as String?
storeFile = (keyProps["storeFile"] as String?)?.let { file(it) }
storePassword = keyProps["storePassword"] as String?
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
}
}
}
Then build:
flutter build appbundle --release --dart-define-from-file=connection.json # for Google Play (.aab)
flutter build apk --release --dart-define-from-file=connection.json # to install directly (.apk)
Output: build/app/outputs/bundle/release/app-release.aab and
build/app/outputs/flutter-apk/app-release.apk. compileSdk and targetSdk are set to
36 explicitly; raise both when Google Play's target-API deadline moves.
iOS
flutter build ipa --release --dart-define-from-file=connection.json
Open ios/Runner.xcworkspace in Xcode once, choose your team under Signing & Capabilities, then
upload build/ios/ipa/*.ipa with Apple's Transporter app or from Xcode's Organizer. You need the paid
Apple Developer Program.
iOS Simulator with Xcode 27
Xcode 27's lipo accepts one architecture per check, while Flutter asks for all simulator architectures
at once, which stopped simulator builds. Every app's ios/Flutter/Debug.xcconfig and
Release.xcconfig therefore contain:
ARCHS[sdk=iphonesimulator*] = arm64
Simulators on Apple silicon Macs need only arm64, and device builds are not affected. On an Intel Mac, remove that line to run the simulator.
Updating
The app
Download the new version from CodeCanyon and read Changelog.txt. ShopKit is source code you have changed,
so an update is a merge, not an install:
- Keep your project in git (
git initand commit before you start customising). - Unzip the new version into a separate folder.
- Copy the changed packages over yours (
shopkit/packages/is where most fixes land), or compare the two folders with a diff tool and take the changes you want. - Run
flutter pub get,flutter analyzeandflutter testin your app folder.
Keeping your changes to colours, names and ids (Branding) and leaving shared screens alone makes updates simple.
The plugin
Upload the new plugin/webkoding-shopkit-connect.zip through Plugins → Add New → Upload Plugin and
choose Replace current with uploaded. App keys, settings and customer data are kept. Existing app builds keep
working; the plugin's REST API is versioned (shopkit/v1).
Troubleshooting
Run flutter doctor -v first for build problems. For store problems, open the plugin's Status and
Logs tabs.
| What you see | Why | Fix |
|---|---|---|
App stops at start with api_url must use https:// | The app refuses to send passwords and tokens over plain HTTP. | Put the store on HTTPS (most hosts include a free Let's Encrypt certificate). Plain http:// is accepted only for localhost, 127.0.0.1, 10.0.2.2 (Android emulator) and *.local test sites. |
The connection code is not valid JSON / not a ShopKit Connect code | The shell changed the quotes, or only part of the JSON was copied. | Pass the base64 of the JSON or use --dart-define-from-file (see step 4). |
| "This app is not connected to the store. Check the app key." | The key was revoked, mistyped, or belongs to another site. | Create a new key on the App keys tab and rebuild with its JSON. |
| "Store staff accounts cannot sign in to the app" | On purpose: administrator and shop manager accounts never get app tokens, so a phone can never become a back-office login. | Test with a customer account. |
| "Too many attempts. We can email you a sign-in link instead." | Login lock-out protection: 5 wrong passwords per account from one network, or 20 per account from all networks, in 15 minutes (and 20 per network address). | Use the emailed sign-in link the app offers; the owner is never locked out. Or wait 15 minutes. |
| "This account uses two-step verification" | A two-factor plugin protects the account; the app does not support two-step sign-in yet. | Sign in on the website, or use an account without two-step verification. |
| Signed-in requests fail with "You are not signed in" right after a successful sign-in | Some hosts (often Apache with PHP-CGI) strip the Authorization header. | Nothing to change in the app: it also sends the token as X-ShopKit-Token. If that header is stripped too, ask your host or security plugin to allow it. |
| Status tab: "The site could not reach its own Store API" | A security plugin, firewall or "disable REST API" setting blocks /wp-json/. | Allow wc/store/v1 and shopkit/v1 in that plugin or firewall. |
| Cart empties or "add to cart" fails; cart differs between requests | A cache or CDN caches /wp-json/ responses or strips the Cart-Token header the WooCommerce Store API uses for the app's cart. | Exclude /wp-json/ (and ?rest_route=) from page caching and pass the Cart-Token, X-ShopKit-Key and X-ShopKit-Token headers through. |
| Status tab: "Plain permalinks are in use" | Settings → Permalinks is on "Plain". | The app works anyway through ?rest_route=, but choose any other permalink setting (for example "Post name"): it is what WooCommerce and caches expect. The connection JSON's api_url follows the setting, so create the key after changing it. |
| Checkout page says "This checkout link has expired" or "has already been used" | The hand-off link is valid for 5 minutes and once. | Go back to the app and tap checkout again. |
| "This browser is signed in to the store with another account" | The in-app browser still has another customer's website session. | Sign out on the website in that browser, then check out again from the app. |
| Sign-up is missing in the app | WooCommerce → Settings → Accounts & Privacy does not allow account creation, or the plugin's registration switch is off. | Turn both on. |
| No push messages arrive | The driver is still Log only, the service account path is wrong, or the app has no Firebase yet. | Check the Status tab ("Push (Firebase)") and the Logs tab; follow Push notifications for the app side. |
| CORS errors in a browser console | Browsers enforce CORS; phones do not. The apps are built for iOS and Android. | Run on a phone, emulator or simulator. A web build of the app needs your server to send CORS headers for /wp-json/. |
| Release APK shows no products although debug works | A custom AndroidManifest.xml without the INTERNET permission. | Keep <uses-permission android:name="android.permission.INTERNET"/> in android/app/src/main/AndroidManifest.xml (it is there in every shipped app). |
iOS Simulator build stops in debug_unpack_ios or with a lipo -verify_arch error | Xcode 27 and the simulator architecture setting. | Keep the ARCHS[sdk=iphonesimulator*] = arm64 line (see Release builds); on an Intel Mac remove it. |
Because fresho depends on shopkit_core from path which doesn't exist | The app folder was moved away from shopkit/packages/. | Keep the layout, or use shopkit/tools/extract_template.sh. |
Command PhaseScriptExecution failed (iOS) | Stale CocoaPods or Xcode build data. | |
| Gradle build fails on the first Android run | Android SDK licences, a missing API 36 platform or Java older than 17. | and install "Android API 36" in Android Studio's SDK Manager. |
| "Connect your store" says the store refused the app key | The key was revoked, or the JSON was cut off while copying. | Create a new key on the plugin's App keys tab and scan its QR code. |
| "Connect your store" says ShopKit Connect is not active | The site answered but the plugin is off, or the address in the JSON is not the WordPress site. | Activate the plugin; check the Status tab. |
| No "Connect your store" anywhere | The app was built with SHOPKIT_CONNECTION (a fixed store) or SHOPKIT_HIDE_CONNECT=true. | Expected. Build without them to use the in-app flow. |
| Google Play rejects the upload: "signed in debug mode" | The release build still uses the debug key. | Set up your upload key (Building for Release). |
Third-Party Services & Costs
Read this before you plan a project. ShopKit and the ShopKit Connect plugin have no running cost of their own. Publishing a shop app uses services from other companies. They are separate products, not included in the price of this item, they need your own account, and their prices are set by them and can change. Check each provider's current pricing.
| Service | Needed for | Cost (at the time of writing, October 2026) |
|---|---|---|
| Web hosting for WordPress + WooCommerce, with HTTPS | Live mode | Your hosting plan. WordPress, WooCommerce and the plugin are free. |
| Google Play Console | Publishing on Android | One-off registration fee (US$25 at the time of writing) |
| Apple Developer Program | Publishing on iOS, iOS push | Yearly fee (US$99 per year at the time of writing) |
| Payment gateways (Stripe, PayPal, iyzico...) | Card payments | Per-transaction fees set by the provider. Cash on delivery and bank transfer cost nothing extra. |
| Firebase Cloud Messaging (Google) | Push notifications (optional) | Free of charge to send at the time of writing; other Firebase products are billed by usage. |
Not implemented
Maps, live courier tracking, support chat and augmented reality are not implemented. The screens that show them are sample layouts: they show sample content in demo mode and are hidden in live mode. Making any of them real needs a paid third-party service at your own extra cost.
The Nest theme's "view in your room" card is a static UI layout. It has no AR functionality, no camera access and no 3D rendering, and no AR package is bundled. Real AR needs a third-party AR SDK or a hosted 3D/AR commerce service (monthly or per-view fees), paid 3D models of each product, and model hosting, all at your own extra cost.
For developers
Architecture
shopkit/packages/
shopkit_core UI only: screens S01-S48, Sk* widgets, 10 themes, fonts, translations.
Never imports HTTP, the domain or the API; screens take data and callbacks.
shopkit_domain Models and repository interfaces (catalog, cart, checkout, orders,
auth, account, wishlist, notifications, config). Money is integer minor units.
shopkit_data_mock The sample store implementing every interface, per theme.
shopkit_data_woo The same interfaces against the WooCommerce Store API (wc/store/v1)
and the plugin (shopkit/v1).
shopkit_app Shared app runtime: "Connect your store" (QR scan / paste, kept in the
keychain, switch without rebuild) and optional Firebase push.
shopkit/templates/<app>/lib/
main.dart demo store, the store connected in the app, or SHOPKIT_CONNECTION
router.dart go_router map and guards
state/ ShopSession (config, user, cart, wishlist), Loader (loading / error / retry)
pages/ one page per route: loads data, maps it to view models, renders a screen
ui/mappers.dart domain model → view model
screens/ the niche screens (E01, A01...)
How the app talks to the store
- Every plugin request carries
X-ShopKit-Key(the app key). A signed-in customer addsAuthorization: Bearerand the same token asX-ShopKit-Token. - Catalog, cart and checkout use WooCommerce's Store API; the cart keeps its
Cart-Token. - Access tokens expire after 1 hour and are refreshed once for all waiting requests; refresh tokens last 30 days,
a session at most 180 days. Tokens are stored hashed on the server and in the phone's secure storage
(Keychain / EncryptedSharedPreferences via
flutter_secure_storage). - No WooCommerce consumer key or secret is ever in the app.
- The full endpoint contract is
shopkit/backends/wordpress/API.md.
Tests (run on 5 October 2026)
| Folder | Tests | Result |
|---|---|---|
shopkit/packages/shopkit_core | 34 | passed |
shopkit/packages/shopkit_data_mock | 326 | passed |
shopkit/packages/shopkit_data_woo | 96 | passed |
shopkit/packages/shopkit_app | 28 | passed |
shopkit/packages/shopkit_domain | 33 | passed |
shopkit/templates/aura | 407 | passed |
shopkit/templates/core_kit | 422 | passed |
shopkit/templates/electro | 414 | passed |
shopkit/templates/fold | 433 | passed |
shopkit/templates/fresho | 418 | passed |
shopkit/templates/glow | 418 | passed |
shopkit/templates/nest | 422 | passed |
shopkit/templates/pawly | 485 | passed |
shopkit/templates/peak | 467 | passed |
shopkit/templates/showcase | 244 | passed |
shopkit/templates/tods | 511 | passed |
| Total | 5,158 | all passed |
Run them with flutter test in any of these folders. Every app has a test that paints each of its screens and
fails on any layout or rendering error. The plugin is tested separately with a PHPUnit suite on a real WordPress + WooCommerce (152 tests, all
passing on 5 October 2026); that suite is our development tooling and is not part of the download.
Design files no design software needed
design-source/ holds the original design of every screen and the app icon. You do not need Photoshop,
Sketch, Figma or XD: the designs are web pages that open in your browser, and the icon is a PNG.
| File or folder | What it is | Open it with |
|---|---|---|
design-source/START-HERE.html | Index of every design file in plain language | A web browser |
design-source/README.txt | The same index as plain text | A text editor |
design-source/screens/ | The design of all screens as web pages, 390 × 844 px, one page per theme plus components and typography | A web browser |
design-source/assets/app-icon.png | The app icon, 1024 × 1024 PNG. Replace it with yours (Branding, step 3). | Any image viewer or editor |
A screen's code in the designs is the name of its Dart file: S17 →
shopkit/packages/shopkit_core/lib/screens/core/s17_product_detail.dart, E05 →
shopkit/templates/electro/lib/screens/e05.dart. The designs are the reference; you change the app in the
Dart theme files, not in the HTML. Some live-mode screens differ from the designs on purpose, where WooCommerce has
different data (for example the filter sheet offers "On sale" and "In stock" instead of "Free shipping").
Changelog
2.0.0 (October 2026)
ShopKit becomes a mobile app for a real WooCommerce store. Every app still runs offline on its sample store.
- New: Webkoding ShopKit Connect for WooCommerce, a free companion plugin: app keys with connection JSON and QR code, customer sign-in with hashed, revocable tokens and lock-out-proof rate limits, address book, wishlist, order history with tracking numbers, notification feed, push through Firebase Cloud Messaging, and a one-time hand-off of the app cart to your own checkout page.
- New:
shopkit_data_woo, the WooCommerce data layer shared by all apps; live mode in all 11 apps with one--dart-define. - New: "Connect your store" in every app: scan the plugin's QR code or paste its JSON, no rebuild; hidden in builds with a fixed store.
- New: optional push through Firebase Cloud Messaging in every app (off until you add your Firebase project); tapping an order notification opens the order.
- New: the store's logo on every splash screen; Core Kit takes the store's primary colour as its accent.
- New: payments: cash on delivery, bank transfer and cheque in the app; all other gateways on your checkout page in a secure web view.
- New: English, Arabic (right to left) and Turkish in every app and in the plugin.
- New: a shared sample store with license-safe bundled photos; 5,158 automated tests.
- Changed: fonts are bundled; nothing is downloaded at run time.
- Changed:
android/andios/ship with every app;flutter create .is no longer needed. iOS 15.0 minimum; simulator builds work with Xcode 27. - Changed: screens without WooCommerce data are hidden in live mode instead of showing sample content.
- Fixed: release Android builds were missing the
INTERNETpermission.
1.0.0 (July 2026)
First release: 192 screens (48 Core Kit + 144 across 9 niche themes) on sample data, 10 themes, the showcase app.
Support
Please read Troubleshooting first. Then contact us through the Support tab
on the item page on CodeCanyon, with your operating system, the output of flutter doctor -v, the app folder you
use and, for store problems, a screenshot of the plugin's Status tab. Questions about setup, branding and the plugin are
welcome; custom development is not included in the licence.