Open sluedecke opened 3 years ago
When it comes to alternative approaches, after some research I came up with the modifications below. They assume that you use capacitor v3.
Add this to MainActivity.java::onCreate
(Sources: capacitor issue 1655, Stack Overflow answer):
if(Build.VERSION.SDK_INT >= 24 ){
ServiceWorkerController swController = ServiceWorkerController.getInstance();
swController.setServiceWorkerClient(new ServiceWorkerClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
return bridge.getLocalServer().shouldInterceptRequest(request);
}
});
}
Add a list of your domains incl. server.hostname / localhost to Info.plist, e.g.:
<key>WKAppBoundDomains</key>
<array>
<string>192.168.0.3</string>
<string>127.0.0.1</string>
<string>localhost</string>
</array>
Enable limitsNavigationsToAppBoundDomains
in your src-capacitor/capacitor.config.json
and set server.url
:
{
"appId": "your.fancy.app.id",
"appName": "Your Fancy app",
"bundledWebRuntime": false,
"npmClient": "yarn",
"webDir": "www",
"ios": {
"limitsNavigationsToAppBoundDomains": true
},
"server": {
"url": "http://192.168.0.3"
}
}
If you are stuck with capacitor v2, this might help:
Add this to node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController.swift::configureWebView
(Sources: capacitor issue 4122, flirt.dev on iOS 14 and service workers):
// 2021-10-07 GUIDE enable bound domains / service worker
if #available(iOS 14.0, *) {
configuration.limitsNavigationsToAppBoundDomains = true
} else {
// Fallback on earlier versions
}
build twice
# build your client normally to get all the icons generated / names set etc.
quasar build -m capacitor -T ios
# build AGAIN, but this time the app as PWA only and copy it into src-capacitor
quasar build -m pwa
rm -rf src-capacitor/www/*
cp -r dist/pwa/* src-capacitor/www
pushd src-capacitor
npx cap sync
popd
# [iOS] edit capacitor.config.json to have the server url set
Open app in IDE or do stuff with gradlew
/ xcodebuild
@sluedecke I was also thinking about this for a while. The solution in my mind is to add some configuration to quasar.conf.js
, similar to how SSR+PWA works. The default value will be false, when you set that option to true, or the workbox options object(e.g. quasar.conf.js > capacitor > pwa = true | { /* workboxOptions to be overridden */ }
or quasar.conf.js > cordova > pwa = true | { /* workboxOptions to be overridden */ }
) and then run quasar dev|build -m cordova|capacitor -T android|ios
and it would also generate and include the service worker. I made some experimentation about the solution, but haven't finished or tested it yet. Please let me know what you think about the solution.
@yusufkandemir This sounds awesome. It would be great to have a MOBILE + PWA combo and also from consistency pov, your proposal about how to enable it sounds the right way. +1
@yusufkandemir such a solution would be great! One might need to make the changes in the native bridge, too.
My alternative solution mentioned in the initial post (prefetching) does work properly on Android! BUT: if the installation of the service worker fails in any way (in my case the __WB_MANIFEST contained an entry for .gitignore
which is an error), the service worker will silently be ignored.
And I made it work in iOS, too!
The IMPORTANT difference is: data included in the native app (all the JavaScript logic, pages, etc.) is loaded by capacitor itself, everything else (e.g. resources from the backend server) is handed over to the fetch mechanism of the platforms webview implementation. BUT:
On Android these included resources are configured to have http://localhost/service-worker.js
. This works just fine.
On iOS these ressources are configured to have capacitor://localhost/service-worker.js
. Webkit refuses to load service workers from non http/https schemes (see https://github.com/ionic-team/capacitor/issues/4752).
Details on capacitor.config.json: https://capacitorjs.com/docs/config
The solution for iOS is to configure a server url in the capacitor.config.json manually (it will be overridden by quasars build mechanism). Although this is discouraged, there are quite some reports that such apps are accepted in the App Store.
I have updated https://github.com/quasarframework/quasar/issues/10934#issuecomment-939244614 accordingly.
@sluedecke May I ask where is this 'MainActivity.java::onCreate' located?
@sluedecke May I ask where is this 'MainActivity.java::onCreate' located?
On my installation it can be found here (app package name is net.currit.guide, yours will differ):
src-capacitor/android/app/src/main/java/net/currit/guide/MainActivity.java
For the records: so ... since I did not get it to work properly after spending another day, I have chosen this way:
Code in build.gradle:
android {
buildTypes {
release {
buildConfigField "String", "WEB_ADDRESS", '"https://somewhere.in.the.inter.net"'
}
}
}
Code in MainActivity.java::onCreate:
WebView webView = getBridge().getWebView();
WebSettings settings = webView.getSettings();
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // load from cache, even if expired
webView.loadUrl(BuildConfig.WEB_ADDRESS);
Is your feature request related to a problem? Please describe.
My web app uses a service worker to capture fetch requests from the browser and add an authentication header. E.g. for all
<img src=.../>
tags and similar. This works well for a web app deployed as pwa.Another use case is to do some extensive prefetching within the service worker in order to go offline with the app.
This does not work at all as a capacitor app since:
quasar build -m capacitor -T ...
builds an spa and not the pwa equivalentDescribe the solution you'd like
I would love to have an option to deploy my PWA as a capacitor project by adding a new mode to
quasar dev/build
or some modifier to the capacitor mode.Describe alternatives you've considered
Alternative is to add the authentication header as a query parameter to the
<img src=.../>
and adapt my server to look for authentication in both the request headers and query parameters. This is implemented and works.For prefetching one could move the logic from the service worker back into the app itself. I did not test that yet.