To convert a Bootstrap site to an APK, download bootstrap.min.css and bootstrap.bundle.min.js (plus Bootstrap Icons if used) into the project instead of loading them from a CDN, make paths relative, close modals and offcanvas menus on the Android back button, then ZIP the folder with index.html at the top and build it with an HTML-to-APK converter.
Key takeaways
- Bundle Bootstrap's CSS and JS bundle locally — CDN copies fail offline.
- Bootstrap Icons need its
fonts/folder beside the CSS file. - Map the back button to closing modals and the offcanvas menu.
- Swap the top navbar for a bottom nav or keep it — both work.
1. Replace the CDN links
The starter template loads Bootstrap from jsDelivr. Download the compiled files from getbootstrap.com (or npm i bootstrap and copy from node_modules/bootstrap/dist/) and reference them locally:
<link href="vendor/bootstrap/bootstrap.min.css" rel="stylesheet">
<link href="vendor/bootstrap-icons/bootstrap-icons.min.css" rel="stylesheet">
...
<script src="vendor/bootstrap/bootstrap.bundle.min.js"></script>Bootstrap Icons' CSS refers to fonts/bootstrap-icons.woff2 relative to itself, so copy the fonts folder next to the CSS. If icons appear as empty squares in the app, this is the cause.
2. Check the viewport and theme colour
Bootstrap's template already includes the viewport tag. Add viewport-fit=cover if you will run full-screen, and set Bootstrap's colour mode to follow the phone:
<html lang="en" data-bs-theme="auto">
<script>
// Bootstrap 5.3 colour modes: follow the system setting
const mq = matchMedia('(prefers-color-scheme: dark)');
const apply = () => document.documentElement.setAttribute('data-bs-theme', mq.matches ? 'dark' : 'light');
apply(); mq.addEventListener('change', apply);
</script>3. Make the back button close modals and menus
In the app, Android's back button navigates WebView history. A Bootstrap modal does not create a history entry, so back skips past it — or closes the app. Push a history state when one opens, and close it on popstate:
document.addEventListener('show.bs.modal', () => history.pushState({ layer: 1 }, ''));
document.addEventListener('show.bs.offcanvas', () => history.pushState({ layer: 1 }, ''));
window.addEventListener('popstate', () => {
document.querySelectorAll('.modal.show').forEach(m => bootstrap.Modal.getInstance(m)?.hide());
document.querySelectorAll('.offcanvas.show').forEach(o => bootstrap.Offcanvas.getInstance(o)?.hide());
});
// closing with the X or backdrop should also remove the extra history entry
['hidden.bs.modal', 'hidden.bs.offcanvas'].forEach(ev =>
document.addEventListener(ev, () => { if (history.state && history.state.layer) history.back(); }));4. Multi-page Bootstrap sites
A theme with index.html, about.html and contact.html works as is — links between pages are ordinary navigation inside the app, and back returns to the previous page. Only check that links are relative (about.html, not /about) and that every page has the same <head> assets.
5. Small changes that make it feel like an app
- Use
.navbar.fixed-bottomwith three or four icon links for primary navigation, or keep the collapsing top bar. - Add
.btn-lgto primary buttons; default buttons are 38px tall, below the 48px touch target. - Remove the footer with copyright and social links — apps rarely have one.
- Replace
.containerwith.container-fluidon small screens to use the full width.
Run the mobile UI checklist for the rest.
6. Build
ZIP the folder's contents (with index.html at the top level) and build it in HTML & ZIP to APK Builder. Bootstrap's CSS and JS bundle add roughly 100 KB gzipped — far under the free plan's 5 MB.
Frequently asked questions
Does Bootstrap work inside an Android WebView?
Yes. Bootstrap 5 targets current Chromium, which is what Android System WebView is. Its responsive grid, components and JavaScript plugins all work.
Do I need jQuery for Bootstrap in an APK?
Not for Bootstrap 5, which dropped jQuery. Bootstrap 4 themes need jQuery and Popper — bundle both locally.