How is your experience with the OutSystems Community?
12
Views
2
Comments
Facing issue in download pdf in mobile
Question

Hi ,We are facing an issue with PDF download on mobile devices.We have a Reactive Web Application (PWA) developed in OutSystems 11. When the same application is accessed from a desktop browser, PDF download works correctly. However, when accessed through the mobile app/PWA, the PDF is not getting downloaded.Could you please help investigate the issue? Also let us know if there are any known limitations or additional configurations required for PDF download in mobile browsers/PWA applications.Details:

  • Platform: OutSystems 11 Reactive Web App (PWA)
  • Desktop: PDF download working fine
  • Mobile App/PWA: PDF download not working
  • Issue observed while downloading generated PDF files

Please suggest the required checks or a solution. 

2025-07-15 08-35-04
Pravin Rahangdale

I faced a similar issue with PDF downloads in an OutSystems 11 Reactive Web Application (PWA). The PDF download worked correctly on desktop browsers but did not work on mobile devices.


I resolved this issue using the following approach.


### 1. Add the FileSaver.js script


First, include the following FileSaver.js library to handle file-saving functionality.


```javascript

var saveAs = saveAs || function(e) {

    "use strict";

    if (typeof e === "undefined" ||

        typeof navigator !== "undefined" &&

        /MSIE [1-9]\./.test(navigator.userAgent)) {

        return;

    }


    var t = e.document,

        n = function() {

            return e.URL || e.webkitURL || e;

        },

        r = t.createElementNS(

            "http://www.w3.org/1999/xhtml", "a"

        ),

        o = "download" in r,

        a = function(e) {

            var t = new MouseEvent("click");

            e.dispatchEvent(t);

        },

        i = /constructor/i.test(e.HTMLElement) || e.safari,

        f = /CriOS\/[\d]+/.test(navigator.userAgent),

        u = function(t) {

            (e.setImmediate || e.setTimeout)(function() {

                throw t;

            }, 0);

        },

        s = "application/octet-stream",

        d = 1e3 * 40,

        c = function(e) {

            var t = function() {

                if (typeof e === "string") {

                    n().revokeObjectURL(e);

                } else {

                    e.remove();

                }

            };

            setTimeout(t, d);

        },

        l = function(e, t, n) {

            t = [].concat(t);

            var r = t.length;

            while (r--) {

                var o = e["on" + t[r]];

                if (typeof o === "function") {

                    try {

                        o.call(e, n || e);

                    } catch (a) {

                        u(a);

                    }

                }

            }

        },

        p = function(e) {

            if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)) {

                return new Blob([

                    String.fromCharCode(65279), e

                ], {

                    type: e.type

                });

            }

            return e;

        },

        v = function(t, u, d) {

            if (!d) {

                t = p(t);

            }


            var v = this,

                w = t.type,

                m = w === s,

                y,

                h = function() {

                    l(v, "writestart progress write writeend".split(" "));

                },

                S = function() {

                    if ((f || m && i) && e.FileReader) {

                        var r = new FileReader();

                        r.onloadend = function() {

                            var t = f ? r.result :

                                r.result.replace(

                                    /^data:[^;]*;/,

                                    "data:attachment/file;"

                                );

                            var n = e.open(t, "_blank");

                            if (!n) {

                                e.location.href = t;

                            }

                            t = undefined;

                            v.readyState = v.DONE;

                            h();

                        };

                        r.readAsDataURL(t);

                        v.readyState = v.INIT;

                        return;

                    }


                    if (!y) {

                        y = n().createObjectURL(t);

                    }


                    if (m) {

                        e.location.href = y;

                    } else {

                        var o = e.open(y, "_blank");

                        if (!o) {

                            e.location.href = y;

                        }

                    }


                    v.readyState = v.DONE;

                    h();

                    c(y);

                };


            v.readyState = v.INIT;


            if (o) {

                y = n().createObjectURL(t);

                setTimeout(function() {

                    r.href = y;

                    r.download = u;

                    a(r);

                    h();

                    c(y);

                    v.readyState = v.DONE;

                });

                return;

            }


            S();

        },

        w = v.prototype,

        m = function(e, t, n) {

            return new v(e, t || e.name || "download", n);

        };


    if (typeof navigator !== "undefined" &&

        navigator.msSaveOrOpenBlob) {

        return function(e, t, n) {

            t = t || e.name || "download";

            if (!n) {

                e = p(e);

            }

            return navigator.msSaveOrOpenBlob(e, t);

        };

    }


    w.abort = function() {};

    w.readyState = w.INIT = 0;

    w.WRITING = 1;

    w.DONE = 2;

    w.error = w.onwritestart = w.onprogress =

        w.onwrite = w.onabort = w.onerror =

        w.onwriteend = null;


    return m;

}(typeof self !== "undefined" && self ||

  typeof window !== "undefined" && window ||

  this.content);


if (typeof module !== "undefined" && module.exports) {

    module.exports.saveAs = saveAs;

} else if (typeof define !== "undefined" &&

    define !== null && define.amd !== null) {

    define("FileSaver.js", function() {

        return saveAs;

    });

}

```


### 2. Add the following JavaScript to download the file


After adding the FileSaver.js script, use the following JavaScript in the appropriate JavaScript element to convert the Base64 file content into a binary buffer and save the file.


```javascript

function fixBinary(base64Str) {

    var base64Array = base64Str.split(",");

    var base64Raw = base64Array.length > 1

        ? base64Array[1]

        : base64Array[0];


    var bin = atob(base64Raw);


    var length = bin.length;

    var buf = new ArrayBuffer(length);

    var arr = new Uint8Array(buf);


    for (var i = 0; i < length; i++) {

        arr[i] = bin.charCodeAt(i);

    }


    return buf;

}


var binary = fixBinary($parameters.FileContent);

var blob = new Blob([binary], {

    type: $parameters.FileType

});


cordova.plugins.saveDialog.saveFile(

    blob,

    $parameters.FileName

).then(function() {

    $parameters.Success = true;

    $resolve();

}).catch(function(reason) {

    $parameters.Success = false;

    $parameters.ErrorMsg = reason;

    $resolve();

});

```


### Important notes

- Ensure that the required Cordova file-saving plugin is installed and configured.

- The second script uses `cordova.plugins.saveDialog.saveFile()`, which requires a compatible Cordova environment; it will not work directly in a standard mobile browser or standalone PWA without that plugin.

- Make sure the input parameters `FileContent`, `FileType`, and `FileName` contain the correct values.


I hope this helps anyone facing a similar PDF download issue in OutSystems 11 Reactive Web Applications.

FileSavePlugin.txt
FileMobileDownload.txt
2019-01-07 16-04-16
Siya
 
MVP

@Chandra Vikas Sharma : The logic used to download files in a web application may not work when the application is packaged as an IPA/APK. For native builds, one option you could try is using the Social Sharing plugin (https://www.outsystems.com/forge/component-overview/7270/easy-social-sharing-plugin-o11). At a high level the algorithm is 

  1. Get the binary content
  2. Check if it's native ( by checking if plugin is present) if so invoke the social sharing plugin  with base64 content of your file.
  3. Else use the js code to download the content.

I have attached a sample implementation for your reference. Do not remove the reference to Social Sharing Plugin even though none of its methods are directly referenced else it will fail when you compile to ipa / apk.  btw you can refer any of the Social Sharing Plugin as long as its referring https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin 

TestDownload.oml
Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.