3

I am developing an Android app from which I want to launch MS office apps to view and edit office files. For example, open a docx stored locally in the device for editing in MS-Word mobile app.

Previously we were opening such file with a file URI passed in an intent with e.g. the "com.microsoft.office.word" package name. The file would open in Word for Android and the user could edit it and save it. No problem.

Now we had to change so that we use the FileProvider class of Android with the permissions for reading and writing. With this implementation other apps can edit the files but Microsoft Office apps for Android are opened in read-only mode with no option to change it.

This seem to be a common issue that happens to others too, as seen in other stackoverflow questions:

When using Android file provider, files don't have correct permissions despite FLAG_GRANT_WRITE_URI_PERMISSION being flagged in intent

and

Xamarin.Forms Android FileProvider: GrantWriteUriPermission not always working

I have also found this link with information about how to invoke the office apps in msdn, but it seems quite incomplete and I haven't been able to make it work with an intent and a local file (I just don't know how to send the ms-word:ofe|u|file so that it recognizes it, it always complains it cannot find the file).

Does anyone know a way to open a local file in edit mode from an android app in microsoft office for Android using FileProvider?

I haven't posted any code as it is no issue with it. Any other app works fine, but Microsoft Office apps.

Jorge
  • 111
  • 1
  • 7

1 Answers1

2

I wrote a common open routine and then broke out individual file types like below. I haven't had issues after doing the following. Hopefully this helps. (note - I only added the word call - but use the types from the SO article here(What is a correct mime type for docx, pptx etc?)

public static Java.IO.File CopyDocuments(Java.IO.File source, string realName)
{

    //string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments); <-- old method
    string path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
    if (!System.IO.Directory.Exists(Path.Combine(path, "appname")))
        System.IO.Directory.CreateDirectory(Path.Combine(path, "appname"));

    string dbPath = Path.Combine(path,"appname", realName);
    Java.IO.File destination = new Java.IO.File(dbPath);

    try
    {
        //if (destination.Exists())
        //    destination.Delete();

        if (!destination.Exists())
        {
            using (FileStream fs = new FileStream(source.AbsolutePath, FileMode.Open, FileAccess.Read))
            {
                using (var br = new BinaryReader(fs))
                {
                    using (var bw = new BinaryWriter(new FileStream(dbPath, FileMode.Create)))
                    {
                        byte[] buffer = new byte[2048];
                        int length = 0;
                        while ((length = br.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            bw.Write(buffer, 0, length);
                        }
                    }
                }
            }
        }

        return destination;
    }
    catch (Exception ex)
    {
        Toast.MakeText(Xamarin.Forms.Forms.Context, "Error Copying: " + ex.Message, ToastLength.Long).Show();
    }
    return null;
}

public void LaunchApp(string fileLocation, string realName)
{
    var file = new Java.IO.File(fileLocation);

    if (!file.Exists())
        return;

    file = CopyDocuments(file, realName);

    Intent intent = null;
    var extension = System.IO.Path.GetExtension(fileLocation).ToLower();

    switch (extension)
    {
        case ContentService.DocxExtension:
            intent = ReturnWord(file, true);
            break;
        case ContentService.DocExtension:
            intent = ReturnWord(file, false);
            break;
        case ContentService.TxtExtension:
        case PlayerLync.Services.ContentService.RtfExtension:
            intent = ReturnText(file);
            break;
        case ContentService.XlsExtension:
            intent = ReturnExcel(file, false);
            break;
        case ContentService.XlsxExtension:
            intent = ReturnExcel(file, true);
            break;
        case ContentService.PPExtension:
            intent = ReturnPowerPoint(file, false);
            break;
        case ContentService.PPXExtension:
            intent = ReturnPowerPoint(file, true);
            break;
        case ContentService.Mp3Extension:
            //contentType = ContentType.Audio;
            break;
        default:
            //contentType = ContentType.Unknown;
            break;
    }

    try
    {
        Xamarin.Forms.Forms.Context.StartActivity(intent);
    }
    catch (Exception ex)
    {
        ... log error
    }
}

private Intent ReturnWord(Java.IO.File file, bool isEx)
{
    var intent = new Intent(Intent.ActionView);
    Android.Net.Uri uri = FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "your_package.fileprovider", file);// --> old method Android.Net.Uri.FromFile(file); //
    intent.AddFlags(ActivityFlags.GrantReadUriPermission);
    intent.AddFlags(ActivityFlags.GrantWriteUriPermission);
    intent.AddFlags(ActivityFlags.GrantPersistableUriPermission);
    intent.PutExtra(Intent.ExtraStream, uri);
    if (!isEx)
    {
        intent.SetDataAndType(uri, "application/vnd.msword");
    }
    else
    {
        intent.SetDataAndType(uri, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
    }
    return intent;
}

Place this all in Android project and do a custom renderer to access it from Xamarin Forms

Dave Friedel
  • 978
  • 11
  • 19