function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
vamsi@sfmobilevamsi@sfmobile 

Download Content from Saleforce using Salesforce mobile SDK and Phonegap

We are developing a mobile app using salesforce mobile sdk for android(and ios too) and phonegap. This requires downloading Salesforce Content(Content can be a file of any type/extension) directly and saving it into mobile device.

We tried below url which exposes the content of the Salesforce Content document.

https://salesforce.com/services/data/v23.0/sobjects/ContentVersion/06890000000wo1zAAA/VersionData.

Since the above url doesnt allow direct download of file, we are parsing the content and writing it into a file to save in mobile device.

 

//This function is invoked when download link is clicked and dwnldDocParams contains saleforce content record id and filename

function downloadFileToDevice(dwnldDocParams){                                

                var dwnldDocId = dwnldDocParams.substring(0,18);

                var fileNameWithExt = dwnldDocParams.substring(18);

                forcetkClient.getContentData(dwnldDocId, onSuccessContentData, onErrorSfContentData);

}

 

forcetk.Client.prototype.getContentData = function(recordId, callback, error) {

        var query = '/' + this.apiVersion + '/sobjects/ContentVersion/'+recordId+'/VersionData'

        this.ajaxForContent(query, callback, error);

}

               

forcetk.Client.prototype.ajaxForContent = function(path, callback, error, method, payload, retry) {

        var that = this;

        var url = this.instanceUrl + '/services/data' + path;

                                //This is the sample url

                                //https://salesforce.com/services/data/v23.0/sobjects/ContentVersion/06890000000wo1zAAA/VersionData

                               

        $j.ajax({

            type: method || "GET",

            async: this.asyncAjax,

            url: (this.proxyUrl !== null) ? this.proxyUrl: url,

                                               

                                                contentType: 'application/octetstream', //since the response sent by salesforce has Content-type : application/octetstream for content of any type(text,image,docx..)

           

                                                cache: false,

            processData: false,

            data: payload,

            success: callback,

            error: (!this.refreshToken || retry ) ? error : function(jqXHR, textStatus, errorThrown) {

                if (jqXHR.status === 401) {

                    that.refreshAccessToken(function(oauthResponse) {

                        that.setSessionToken(oauthResponse.access_token, null,

                        oauthResponse.instance_url);

                                                                                                that.ajaxForContent(path, callback, error, method, payload, true);

                    },

                    error);

                } else {

                    error(jqXHR, textStatus, errorThrown);

                }

            },

 

                                                dataType: "text", //valid datatypes are text,json,xml,html,jsonp

                                               

            beforeSend: function(xhr) {

                if (that.proxyUrl !== null) {

                    xhr.setRequestHeader('SalesforceProxy-Endpoint', url);

                }

                xhr.setRequestHeader(that.authzHeader, "Bearer " + that.sessionId);

                xhr.setRequestHeader('X-User-Agent', 'salesforce-toolkit-rest-javascript/' + that.apiVersion);

                                               

                if (that.userAgentString !== null) {

                    xhr.setRequestHeader('User-Agent',that.userAgentString);

                }

            }

        });

    }         

               

//Success callback function         

function onSuccessContentData(response) {

    var $j = jQuery.noConflict();

                //Phonegap method

    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,

                               function (fileSystem) {

                //fileSystem.root.getFile("readme.txt", {create: true, exclusive: false}, //here file name is hardcoded just for static verification for writing into files of different types

                fileSystem.root.getFile("testimage.png", {create: true, exclusive: false},

                //fileSystem.root.getFile("sampleDoc.docx", {create: true, exclusive: false},

                function (fileEntry) {

                                        fileEntry.createWriter(

                                        function gotFileWriter(writer) {

                                                                                writer.onwrite = function(evt) {

                                                                                console.log("write success");

                                                                                };

                                                                                writer.write(response);

                                                    }, fail);

                                    }, fail);

                }, fail);

}

 

The above code works only for text files. For text files response is text only.For other files, we could observe Though we could get response for files of other types also and write into file in device, they could not be viewed. May be the response sent as octetstream need to processed in some way before writing into file. Dont know if there is any issue writing binary data into file using above phonegap function. Any pointers to successfully write content into file (of any type) is  really helpful.

 

Sample response obtained for an image(png) file:

 

07-18 15:11:10.822: D/CordovaLog(1421): >onSuccessContentData&colon;response--"?PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR\u0000\u0000\u0000 \u0000\u0000\u0000?\b\u0002\u0000\u0000\u0000\u0005?v?\u0000\u0000\u0000\u0019tEXtSoftware\u0000Adobe ImageReadyq?e<\u0000\u0000\u0000?IDATx???1\u0012?0\u0010\u0005Pp????\n?86\u0014R?\u0006?`?\u0001,?\u0005\u0016_.??o\"Yp?????.?\u0012\nt\u0000?z??D;?(?\u001e?/?M>?K\u0013??n???\t6???\t\u0016?\u0013?\u0003?\u0004{'???g??'pL?\"??\u001e?;?RJl?5?c,0MS??1??\u0001\u0000\u0000\u0000\u0000r\\??s?a\u0018r??\u000f\u0000\u0000\u0000\u0000\u0000 Kgw???E\u0000\u0000\u0000\u0000\u0000\u0000\u0000[4^??\"S?\u0007\u0000?E?A?$P\"\tN?,??\u0018?>@\u0002C?J$???#??\u0004??\u0004???3?4c????\u0001\u0000\u0000\u0000\u0000?\u0004\b\u001f?v?\u0003\u0000\u0000\u0000\u0000\u0000\u0000|?\u0007?B?\u0019?|??\u0000\u0000\u0000\u0000IEND?B`?"

 

 

It would be really great if there is any way to download the file directly from salesforce instead of reading response and writing manually into a file in device.

I could find another url which DIRECTLY DOWNLOADS THE FILE if we are currently in salesforce session. I tried this url in place of url in above scenario but no progress..

https://<instance>content.force.com/sfc/servlet.shepherd/version/download/<ContentVerion record Id>

Eg: https://c.ap1.content.force.com/sfc/servlet.shepherd/version/download/06890000000CZjT.

 

YD98YD98
I really enjoyed this great article. Check out this unrelated piece of fanfiction I wrote about the TV show unlockmy tv apk (http://www.unlockmytvapp.com), this will be great for someone who crazy about tv shows !!!