Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat](ios) Add ios assets-library url support #259

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,31 @@ The plugin uses [NSURLSession with background session configuration for iOS](htt
tns plugin add nativescript-background-http
```

## Breaking Change
In v5.0 `.uploadFile` and `.multipartUpload` returns a promise with the task instead of a task directly.
This is to allow ios "assets-library" urls to be uploaded (& easily in future ios PHAsset urls).


## Usage

The below attached code snippets demonstrate how to use `nativescript-background-http` to upload single or multiple files.


### Uploading files

Sample code for configuring the upload session. Each session must have a unique `id`, but it can have multiple tasks running simultaneously. The `id` is passed as a parameter when creating the session (the `image-upload` string in the code bellow):

```JavaScript

// file path and url
var file = "/some/local/file/path/and/file/name.jpg";
var url = "https://some.remote.service.com/path";
var name = file.substr(file.lastIndexOf("/") + 1);
const file = "/some/local/file/path/and/file/name.jpg";
const url = "https://some.remote.service.com/path";
const name = file.substr(file.lastIndexOf("/") + 1);

// upload configuration
var bghttp = require("nativescript-background-http");
var session = bghttp.session("image-upload");
var request = {
const bghttp = require("nativescript-background-http");
const session = bghttp.session("image-upload");
const request = {
url: url,
method: "POST",
headers: {
Expand All @@ -43,23 +49,28 @@ var request = {
For a single file upload, use the following code:

```JavaScript
var task = session.uploadFile(file, request);
session.uploadFile(file, request).then( (task) => { /* Do something with Task */ });
```

For multiple files or to pass additional data, use the multipart upload method. All parameter values must be strings:

```JavaScript
var params = [
const params = [
{ name: "test", value: "value" },
{ name: "fileToUpload", filename: file, mimeType: "image/jpeg" }
];
var task = session.multipartUpload(params, request);
session.multipartUpload(params, request).then( (task) => { /* Do something with Task */ } );
```

In order to have a successful upload, the following must be taken into account:

- the file must be accessible from your app. This may require additional permissions (e.g. access documents and files on the device). Usually this is not a problem - e.g. if you use another plugin to select the file, which already adds the required permissions.
- the URL must not be blocked by the OS. Android Pie or later devices require TLS (HTTPS) connection by default and will not upload to an insecure (HTTP) URL.
- If you are going to upload or allow uploading assets-library urls on iOS (i.e. URL's received from the Gallery) you need to add the following to your ios's Info.plist file:
```
<key>NSPhotoLibraryUsageDescription</key>^M
<string>Requires access to photo library.</string>^M
```

### Upload request and task API

Expand Down Expand Up @@ -120,7 +131,7 @@ function progressHandler(e) {
// response: net.gotev.uploadservice.ServerResponse (Android) / NSHTTPURLResponse (iOS)
function errorHandler(e) {
alert("received " + e.responseCode + " code.");
var serverResponse = e.response;
let serverResponse = e.response;
}


Expand All @@ -138,7 +149,7 @@ function respondedHandler(e) {
// response: net.gotev.uploadservice.ServerResponse (Android) / NSHTTPURLResponse (iOS)
function completeHandler(e) {
alert("received " + e.responseCode + " code");
var serverResponse = e.response;
let serverResponse = e.response;
}

// event arguments:
Expand Down
2 changes: 2 additions & 0 deletions demo-angular/app/App_Resources/iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>Requires access to photo library.</string>
</dict>
</plist>
21 changes: 12 additions & 9 deletions demo-angular/app/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class HomeComponent {
request.headers["Should-Fail"] = true;
}

let task: bgHttp.Task;
let taskPromise: Promise<bgHttp.Task>;
let lastEvent = "";
if (isMulti) {
const params = [
Expand All @@ -72,9 +72,9 @@ export class HomeComponent {
{ name: "bool", value: true },
{ name: "fileToUpload", filename: this.file, mimeType: 'image/jpeg' }
];
task = this.session.multipartUpload(params, request);
taskPromise = this.session.multipartUpload(params, request);
} else {
task = this.session.uploadFile(this.file, request);
taskPromise = this.session.uploadFile(this.file, request);
}

function onEvent(e) {
Expand All @@ -97,11 +97,14 @@ export class HomeComponent {
});
}

task.on("progress", onEvent.bind(this));
task.on("error", onEvent.bind(this));
task.on("responded", onEvent.bind(this));
task.on("complete", onEvent.bind(this));
lastEvent = "";
this.tasks.push(task);
taskPromise.then( (task: bgHttp.Task) =>
{
task.on("progress", onEvent.bind(this));
task.on("error", onEvent.bind(this));
task.on("responded", onEvent.bind(this));
task.on("complete", onEvent.bind(this));
lastEvent = "";
this.tasks.push(task);
});
}
}
1 change: 1 addition & 0 deletions demo-server/package.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"start": "npm i && node server.js 8080"
},
"dependencies": {
"formidable": "^1.2.2",
"stream-throttle": "*"
}
}
29 changes: 26 additions & 3 deletions demo-server/server.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var http = require("http");
var fs = require("fs");
var path = require("path");
var formidable = require('formidable');

function start(port, logger) {

Expand All @@ -9,13 +10,33 @@ function start(port, logger) {
try {
var Throttle = require("stream-throttle").Throttle;

if (request.headers["content-type"] && request.headers["content-type"].startsWith("multipart/form-data")) {
const form = formidable({ multiples: true, uploadDir: outDir, keepExtensions: true });
form.parse(request, (err, fields, files) => {

// Make the files array look nicer...
let uploads={};
for (let key in files) {
uploads[key] = files[key].path;
}
console.log("Fields", fields, "Files:", uploads);
logger.log("Done!");

var body = "Upload complete!";
response.writeHead(200, "Done!", { "Content-Type": "text/plain", "Content-Length": body.length });
response.write(body);
response.end();
});
return;
}

var fileName = request.headers["file-name"];
if (logger) {
logger.log(request.method + "Request! Content-Length: " + request.headers["content-length"] + ", file-name: " + fileName);
logger.dir(request.headers);
}

var out = path.join(outDir, "upload-" + new Date().getTime() + "-" + fileName);
var out = path.join(outDir, "upload-" + new Date().getTime() );
if (logger) {
logger.log("Output in: " + out);
}
Expand All @@ -26,7 +47,7 @@ function start(port, logger) {
var shouldFail = request.headers["should-fail"];

// throttle write speed to 4MB/s
request.pipe(new Throttle({ rate: 1024 * 4096 })).pipe(fs.createWriteStream(out, { flags: 'w', encoding: null, fd: null, mode: 0666 }));
request.pipe(new Throttle({ rate: 1024 * 8192 })).pipe(fs.createWriteStream(out, { flags: 'w', encoding: null, fd: null, mode: 0666 }));

request.on('data', function(chunk) {
current += chunk.length;
Expand All @@ -45,7 +66,7 @@ function start(port, logger) {
}
} else {
if (logger) {
logger.log("Data [" + out + "]: " + current + " / " + total + " " + Math.floor(100 * current / total) + "%");
//logger.log("Data [" + out + "]: " + current + " / " + total + " " + Math.floor(100 * current / total) + "%");
}
}
});
Expand Down Expand Up @@ -93,4 +114,6 @@ exports.start = start;
if (process.argv.length === 3) {
var port = parseInt(process.argv[2]);
start(port, console);
} else {
console.log("Args", process.argv.length);
}
2 changes: 2 additions & 0 deletions demo-vue/app/App_Resources/iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,7 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>Requires access to photo library.</string>
</dict>
</plist>
20 changes: 11 additions & 9 deletions demo-vue/app/components/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default {
request.headers["Should-Fail"] = true;
}

let task; // bgHttp.Task;
let taskPromise; // Promise<Task>
let lastEvent = "";

if (isMulti) {
Expand All @@ -97,9 +97,9 @@ export default {
{ name: "bool", value: true },
{ name: "fileToUpload", filename: this.file, mimeType: 'image/jpeg' }
];
task = this.session.multipartUpload(params, request);
taskPromise = this.session.multipartUpload(params, request);
} else {
task = this.session.uploadFile(this.file, request);
taskPromise = this.session.uploadFile(this.file, request);
}

function onEvent(e) {
Expand All @@ -124,13 +124,15 @@ export default {
this.$set(this.tasks, this.tasks.indexOf(task), task);
}

task.on("progress", onEvent.bind(this));
task.on("error", onEvent.bind(this));
task.on("responded", onEvent.bind(this));
task.on("complete", onEvent.bind(this));
lastEvent = "";
taskPromise.then( (task) => {
task.on("progress", onEvent.bind(this));
task.on("error", onEvent.bind(this));
task.on("responded", onEvent.bind(this));
task.on("complete", onEvent.bind(this));
lastEvent = "";
this.tasks.push(task);
});

this.tasks.push(task);
},
onItemLoading(args) {
let label = args.view.getViewById("imageLabel");
Expand Down
2 changes: 2 additions & 0 deletions demo/app/App_Resources/iOS/Info.plist
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>Requires access to photo library.</string>
</dict>
</plist>
20 changes: 11 additions & 9 deletions demo/app/home/home-view-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class HomeViewModel extends Observable {
request.headers["Should-Fail"] = true;
}

let task: bghttp.Task;
let taskPromise: Promise<bghttp.Task>;
let lastEvent = "";
if (isMulti) {
const params = [
Expand All @@ -72,9 +72,9 @@ export class HomeViewModel extends Observable {
{ name: "bool", value: true },
{ name: "fileToUpload", filename: this.file, mimeType: 'image/jpeg' }
];
task = this.session.multipartUpload(params, request);
taskPromise = this.session.multipartUpload(params, request);
} else {
task = this.session.uploadFile(this.file, request);
taskPromise = this.session.uploadFile(this.file, request);
}

function onEvent(e) {
Expand All @@ -97,11 +97,13 @@ export class HomeViewModel extends Observable {
});
}

task.on("progress", onEvent.bind(this));
task.on("error", onEvent.bind(this));
task.on("responded", onEvent.bind(this));
task.on("complete", onEvent.bind(this));
lastEvent = "";
this.tasks.push(task);
taskPromise.then( (task: bghttp.Task ) => {
task.on("progress", onEvent.bind(this));
task.on("error", onEvent.bind(this));
task.on("responded", onEvent.bind(this));
task.on("complete", onEvent.bind(this));
lastEvent = "";
this.tasks.push(task);
});
}
}
5 changes: 3 additions & 2 deletions src/.npmignore
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
scripts/*
scripts/
typings/*
*.map
/node_modules
*.ts
Expand All @@ -7,4 +8,4 @@ tsconfig.json
*.tgz
/package
/platforms/android/**/*
!platforms/android/uploadservice-release.aar
!platforms/android/uploadservice-release.aar
8 changes: 4 additions & 4 deletions src/background-http.android.ts
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ class Session {
this._id = id;
}

public uploadFile(fileUri: string, options: common.Request): Task {
return Task.create(this, fileUri, options);
public uploadFile(fileUri: string, options: common.Request): Promise<Task> {
return Promise.resolve( Task.create(this, fileUri, options) );
}

public multipartUpload(params: Array<any>, options: common.Request): Task {
return Task.createMultiPart(this, params, options);
public multipartUpload(params: Array<any>, options: common.Request): Promise<Task> {
return Promise.resolve( Task.createMultiPart(this, params, options) );
}

get id(): string {
Expand Down
Loading