使用NativeScript在线上传图像

时间:2019-02-13 16:17:57

标签: upload nativescript

我正在开发Nativscript-Vue移动应用,我需要能够从图片库中选择一个文件并将其上传到在线文件管理器(我使用000webhost.com)。

我使用了从NativeScript网站获得的代码示例,并且能够毫无问题地获取图片,但是我无法将其上传到WebHost(日志显示上传成功,并且存在没有显示错误,但由于某些原因我的图片文件夹仍然为空)。

这是我的代码:

    <template>
    <Page class="page">
        <ActionBar title="imagepicker + background-http" class="action-bar"></ActionBar>

        <GridLayout rows="*, auto">
            <GridLayout v-if="!showWelcome" rows="auto auto auto, *">
                <Progress :value="event && event.eventData ? event.eventData.currentBytes : 0"
                    :maxValue="event && event.eventData ? event.eventData.totalBytes : 0">
                </Progress>

                <Label row="1" v-if="event && event.eventData && event.eventData.currentBytes !== NaN"
                    class="m-10 text" :text="'Transferred: ' + event.eventData.currentBytes / 1000 + ' KB'"></Label>

                <Label row="2" class="m-10 text" text="Events"></Label>

                <ListView row="3" for="item in eventLog">
                    <v-template>
                        <StackLayout class="t-12">
                            <Label :text="item.eventTitle" textWrap="true"></Label>
                            <Label v-if="item.eventData && item.eventData.error"
                                :text="item.eventData ? 'Error: ' + item.eventData.error : ''"
                                textWrap="true"></Label>
                            <Label v-if="item.eventData && item.eventData.body"
                                :text="item.eventData ? 'Body: ' + item.eventData.body : ''"
                                textWrap="true"></Label>
                            <Label v-if="item.eventData && item.eventData.raw"
                                :text="item.eventData ? 'Raw: ' + item.eventData.raw : ''"
                                textWrap="true"></Label>
                        </StackLayout>
                    </v-template>
                </ListView>
            </GridLayout>
            <StackLayout v-if="showWelcome" verticalAlignment="middle">
                <Label class="m-10 nativescript-label text" text="{N}"></Label>
                <Label class="m-10 text" v-if="showWelcome" text="This sample app shows how to pick an image with"
                    textWrap="true"></Label>
                <Label class="m-10 text plugin" text="nativescript-imagepicker"></Label>
                <Label class="m-10 text" v-if="showWelcome" text="and upload it using"
                    textWrap="true"></Label>
                <Label class="m-10 text plugin" text="nativescript-background-http"></Label>
            </StackLayout>
            <Button class="m-b-10 m-t-10 t-20" row="1" text="Choose image to upload" @tap="onSelectImageTap($event)"></Button>
        </GridLayout>
    </Page>
</template>

<script>
    import VueRx from "../vue-rx";
    import Vue from "nativescript-vue";

    const app = require("tns-core-modules/application");
    const platform = require("platform");
    const fs = require("file-system");
    const imagePicker = require("nativescript-imagepicker");
    const rxjs = require("rxjs");
    const operators = require("rxjs/operators");
    const bgHttp = require("nativescript-background-http");

    Vue.use(VueRx);
    // Vue.config.silent = false; // uncomment for debugging purposes

    export default {
        data() {
            return {
                showWelcome: true,
                session: bgHttp.session("image-upload"),
                currentFileNameBeingUploaded: ""
            };
        },
        subscriptions() {
            this.event$ = new rxjs.BehaviorSubject({});
            return {
                event: this.event$,
                eventLog: this.event$.pipe(
                    operators.sampleTime(200),
                    operators.concatMap(value => rxjs.of(value)),
                    operators.scan((acc, logEntry) => {
                        acc.push(logEntry);
                        return acc;
                    }, []),
                    // emit only logs for the this.currentFileNameBeingUploaded
                    operators.map(allLogs => allLogs.filter(logEntry => !!logEntry && logEntry.eventTitle && logEntry.eventTitle.indexOf(this.currentFileNameBeingUploaded) > 0))
                )
            };
        },
        methods: {
            onSelectImageTap() {
                let context = imagePicker.create({
                    mode: "single"
                });
                this.startSelection(context);
            },
            startSelection(context) {
                context
                    .authorize()
                    .then(() => {
                        return context.present();
                    })
                    .then(selection => {
                        this.showWelcome = false;

                        let imageAsset = selection.length > 0 ? selection[
                            0] : null;
                        if (imageAsset) {
                            this.getImageFilePath(imageAsset).then(path => {
                                console.log(`path: ${path}`);
                                this.uploadImage(path);
                            });
                        }
                    })
                    .catch(function(e) {
                        console.log(e);
                    });
            },
            uploadImage(path) {
                let file = fs.File.fromPath(path);
                this.currentFileNameBeingUploaded = file.path.substr(
                    file.path.lastIndexOf("/") + 1
                );
                let request = this.createNewRequest();
                request.description = "uploading image " + file.path;
                request.headers["File-Name"] = this.currentFileNameBeingUploaded;

                // -----> multipart upload
                // var params = [{
                //         name: "test",
                //         value: "value"
                //     },
                //     {
                //         name: "fileToUpload",
                //         filename: file.path,
                //         mimeType: "image/jpeg"
                //     }
                // ];
                // var task = this.session.multipartUpload(params, request);
                // <----- multipart upload

                let task = this.session.uploadFile(file.path, request);
                task.on("progress", this.onEvent.bind(this));
                task.on("error", this.onEvent.bind(this));
                task.on("responded", this.onEvent.bind(this));
                task.on("complete", this.onEvent.bind(this));
            },
            createNewRequest() {
                let url;
                // NOTE: using https://httpbin.org/post for testing purposes,
                // you'll need to use your own service in real-world app
                if (platform.isIOS) {
                    url = "https://ipaccovoiturage.000webhostapp.com/pictures";
                } else {
                    url = "https://ipaccovoiturage.000webhostapp.com/pictures";
                }

                let request = {
                    url: url,
                    method: "POST",
                    headers: {
                        "Content-Type": "application/octet-stream"
                    },
                    description: "uploading file...",
                    androidAutoDeleteAfterUpload: false,
                    androidNotificationTitle: "NativeScript HTTP background"
                };
                return request;
            },
            getImageFilePath(imageAsset) {
                return new Promise(resolve => {
                    if (platform.isIOS) {
                        const options = PHImageRequestOptions.new();
                        options.synchronous = true;
                        options.version =
                            PHImageRequestOptionsVersion.Current;
                        options.deliveryMode =
                            PHImageRequestOptionsDeliveryMode.HighQualityFormat;

                        PHImageManager.defaultManager().requestImageDataForAssetOptionsResultHandler(
                            imageAsset.ios,
                            options,
                            nsData => {
                                // create file from image asset and return its path
                                const tempFolderPath = fs.knownFolders
                                    .temp()
                                    .getFolder("nsimagepicker").path;
                                const tempFilePath = fs.path.join(
                                    tempFolderPath,
                                    Date.now() + ".jpg"
                                );

                                nsData.writeToFileAtomically(
                                    tempFilePath, true);
                                resolve(tempFilePath);
                            }
                        );
                    } else {
                        // return imageAsset.android, since it 's the path of the file
                        resolve(imageAsset.android);
                    }
                });
            },
            onEvent(e) {
                let eventEntry = {
                    eventTitle: e.eventName + " " + e.object.description,
                    eventData: {
                        error: e.error ? e.error.toString() : e.error,
                        currentBytes: e.currentBytes,
                        totalBytes: e.totalBytes,
                        body: e.data
                        // raw: JSON.stringify(e) // uncomment for debugging purposes
                    }
                };

                this.event$.next(eventEntry);
            }
        }
    };
</script>

<style scoped>
    .home-panel {
        vertical-align: center;
        font-size: 20;
        margin: 15;
    }

    .description-label {
        margin-bottom: 15;
    }

    .text {
        text-align:
            center;
        font-size: 18px;
    }

    .plugin {
        font-weight: 600;
        font-size: 23px;
    }

    .nativescript-label {
        font-size: 60px;
        background-color: #3d5afe;
        font-weight: 600;
        color: white;
        border-radius: 20px/20px;
        width: 230px;
        height: 230px;
    }
</style>

我以为WebHost可能是问题所在,但是我已经能够使用PHP和HTML插入照片(不幸的是,NativeScript-Vue不允许HTML)。

1 个答案:

答案 0 :(得分:1)

我在纯JavaScript中也遇到了类似的问题。我在上面工作了几天。 @Manoj的答案对我不起作用。我必须使用multipartUpload,因为我要发送其他参数。

确保将请求中的名称参数(fileToUpload)与您的服务期望的名称匹配。就我而言是“文件”。

服务API签名如下:

public async Task<IActionResult> Upload(string listingId, IFormFile file)

我的要求:

const request = {
    url: "yoururl",
    method: "POST",
    headers: {
        "Content-Type": "multipart/form-data",
        "Authorization": token
    },
    description: `Uploading image ${name}`,
    androidAutoDeleteAfterUpload: true,
    androidNotificationTitle: "HTTP background"
};

const params = [
        {
            name: "listingId",
            value: 2
        },
        {
            name: "file", // Note it is not fileToUpload but file instead.
            filename: path,
            mimeType: "image/jpeg"
        }
    ];
    const task = session.multipartUpload(params, request);

我希望它会有所帮助。顺便说一下,Content-Type multipart / form-data和application / octet-stream都对我有用,但是我使用multipart / form-data来保持一致性