Fahad Rehman
Fahad Rehman

Reputation: 1199

IOS NSURLSession Background Uploading how to upload Large Files in Background?

I want to Upload the Large Files (Videos) of 2-3 GB to Server in background with the following requirements

First Method

  1. Uploading should resume if the internet Connection lost and reconnected

  2. Uploading should continue even application is in background

  3. Uploading should resume if user kills the application and comes back

for the Above features what I have implemented

  1. User select the File

  2. Split the File into Chunks Of 1MB and save all the Chunks on the Disk as File

  3. Create the Upload Task Against Each Chunk File and add the File in Background Session

Above Method works but fails in Some Case

  1. If the File Is Larger than 1GB Creating Chunks and Writing Chunks on Disk throw Memory Exception

  2. If I want to Upload the File of 1GB I need extra 1 GB Space to Create Chunks

Second Method

Upload the Original File without creating chunks, in this case, I am not able to resume uploading if network connectivity lost or User Kill the application

My question is What is the best way to upload the Large files in Background Keeping all these points in Mind

I know there are some questions of this type already asked but none of them answer my question

I have spent lot of time Implementing this but can not implement it successfully please help me or give some suggestion what is the best way to complete the above points

Update

I am Using the Following Code to Create Chunks Code is in Xamarin.IOS but i am Ok if some one Provide explantion in Objective C or Swift

public static void SplitFileInChunks( UploadFileInfo UploadFile )
{
        int i = -1;

        long chunkSize = UploadHelper.chunkSize;
        nuint dataLength = (System.nuint)chunkSize; 

        //var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        string directoryPath = UploadHelper.UploadsDirectory;

        int chunkCount = 0;
        NSFileHandle fileHandleRead = NSFileHandle.OpenRead(UploadFile.FilePath);

        fileHandleRead.ReadInBackground();
        //fileHandleRead.WaitForDataInBackground();

        if (fileHandleRead == null)
            return;

        do
        {
            i++;
            ulong index = (ulong)(i * chunkSize);

            var filePath = Path.Combine(directoryPath, UploadFile.ContentGuide + "" + i.ToString());
            //fileHandleRead.SeekToFileOffset(index);

            NSData data = fileHandleRead.ReadDataOfLength(dataLength );
            Console.WriteLine(UploadFile.FileStatus);

            if (data.Length <= 0)
                continue;

            NSFileManager.DefaultManager.CreateFile(filePath, data, attr: null);


            NSError error;
            //data.Save(filePath, true, out error);

            chunkCount++;

            Console.WriteLine("Data Lenght" + data.Length);
            data.Dispose();
            Console.WriteLine("Chunk " + i);
        }

        while ( i * chunkSize <= UploadFile.Size && UploadFile.FileStatus != UploadFileStatus.Aborted );

        fileHandleRead.CloseFile();
        fileHandleRead.Dispose();

        Console.WriteLine("All Files Written sucessuflly");
        UploadFile.TotalChunksCount = chunkCount;

    }

Upvotes: 4

Views: 2649

Answers (1)

dgatwood
dgatwood

Reputation: 10407

That will certainly work, but if you're in control over the software on the other end, you can do better:

  • On the server side:

    • Provide an upload start endpoint (URL) that merely provides a unique ID.
    • Provide an upload data endpoint that takes the unique ID, a POST body, and an optional starting byte offset, and writes the data to a temporary file on the server.
    • Provide an upload status endpoint that takes the unique ID and returns the amount of data it has stored on disk so far.
    • Provide an upload finished endpoint.
  • On the client side:

    • Call the start endpoint and get an ID for the upload.
    • Call the upload data endpoint and start sending data.
    • On failure, call the upload status endpoint to find out how much data the server actually got.
    • Then call the data endpoint and start sending data from that offset, telling the server where you're starting. (On the server, always start writing at that offset into the file even if the length has increased since then, just to be safe.)
    • Upon completion, call the upload finished endpoint.

This architecture also makes it possible to show a status bar fairly easily.

Upvotes: 1

Related Questions