In my app I want to display a PDF which works when...
# multiplatform
t
In my app I want to display a PDF which works when retrieving it over HTTP For Android:
Copy code
AndroidView(
        factory = { context ->
            WebView(context).apply {
                webViewClient = WebViewClient()

                settings.loadWithOverviewMode = true
                settings.useWideViewPort = true
                settings.setSupportZoom(true)
            }
        },
        update = { webView ->
            webView.loadUrl("<https://www.dummy.com/sample.pdf>")
        }
    )
For iOS:
Copy code
UIKitView(modifier = Modifier.fillMaxSize(),
        factory = {
            WKWebView()
        },
        update = { webView ->
            webView.loadRequest(
                NSURLRequest.requestWithURL(
                    NSURL.URLWithString("<https://www.dummy.com/sample.pdf>")!!
                )
            )
        }
    )
What I want to achieve is having the PDF locally on the device to be able to display the PDF without requiring a network connection. I only want to have the PDFs under common, but its not clear to me how (or if at all) I can reference the files from my Android and iOS source set. Any pointers highly appreciated.
s
Not sure does it will help you or not Check it out this repo : https://github.com/swapnil-musale/KMP-PDF-Viewer
t
Thank you! I studied this one, but its also retrieving PDFs form the web and not locally.
s
Yep Then try to save the same base64 inside the file system So next time you don't need to fetch PDF from network resource
t
I just want to put the PDF into
commonMain/resources
and distribute it with the app, then be able to display it from
androidMain
and
iosMain
j
It's easy for the iOS case where you can get URL for resource easily using NSBundle (and then feed the webView with file:// URL), and on Android, you can access is via file://android_asset/<path> where the <path> is path to your assets.
s
If understanding your question properly then you want to view the PDF from local storage in that case 1. Create expect composable function in commonMain 2. In androidMain create actual function impl and render pdf using any third part lib or with system component 3. In iosMain create actual composable fun and use UIKitView and render PDF inside PdfKit componennt
t
@Jan Holešovský I am trying with Android right now and have stored the PDF in
androidMain/res/myfile.pdf
, to check if it can load at least load it from
androidMain
, in code I try loading it with
webView.loadUrl("<file://android_asset/myfile.pdf>")
, but still can’t find it.
j
You need to have that in the assets; https://stackoverflow.com/a/11962112/16670548 seems to describe it nicely
t
“_located in the
assets
folder in the root of the project” :_ In the context of a Compose Multiplatform app, what is the “root” of the project? Would that be directly having a folder called
assets
under
composeApp
? (Which doesn’t work either, just tried …)
j
t
Interesting, storing the file under
androidMain/assets
leaves me with an empty view but no error message. Maybe an issue with my composable. It does not work though when trying to load from
commonMain/assets
, but at least its a hint. Maybe there is a way using MOKO-resources and then handing over “something” to the actual classes …
j
No idea - I'm not familiar with compose; but the webview & assets is a "classic" Android thing, not having much to do with Compose, so IIWY, I'd try to load some trivial html first & debug why it is not showing before trying your luck with MOKO.
You can even connect to the webview & see the browser's console etc. to debug the problems with it and stuff...
t
Loading and displaying PDF from web does work, but my use case requires says “no network” allowed …
j
Sure
I suspect there is still something wrong with accessing the file:///android_asset/...
Unpack your APK and check the file got there, it should be in the assets/ there
etc.
Webview is quite a complex feature, it can take you a while before getting it right for the local file 😉
t
@Jan Holešovský. have some more leads to follow thanks to you!
👍 1
j
One more thing that might help - source code of a complex WebView that not only reads local file(s), but also sets up some back and forth communication between the Android code and the JS code running inside the webview; in case you'll need something like that at some stage: https://github.com/CollaboraOnline/online/blob/master/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java#L349
thank you color 1
👍 1
m
In android, did you give permission to the webview to access files? Because they won't load resources, or assets, or downloaded files right away (besides perhaps intercepted requests). At minimum, you need to call webView.getSettings().setAllowFileAccess(true).
At this point, you should use the asset manager instead, though. https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader
Finally, nothing stops you from putting the files inside the common sourceset and adding a gradle task to copy them into androidMain & iOsMain before compiling. Moko probably does something like that.
431 Views