从Android 7+ / Nougat开始,如何从Android应用程序将图像传递到Instagram

问题描述 投票:0回答:1

我曾经使用以下代码将我的应用程序中的照片发送到Instagram ...

this.Publish(new MaskMessageEvent("Copy ready for Instagram App", true));

    var bytes = e.Result; // get the downloaded data

    /// You must first save your file in PNG or JPEG (preferred) format and use the filename extension ".ig"
    /// Using the iOS Document Interaction APIs you can trigger the photo to be opened by Instagram. 
    /// The Identifier for our Document Interaction UTI is com.instagram.photo, 
    /// and it conforms to the public/jpeg and public/png UTIs. 
    ///  Alternatively, if you want to show only Instagram in the application list 
    /// (instead of Instagram plus any other public/jpeg-conforming apps) you can specify the 
    /// extension class igo, which is of type com.instagram.exclusivegram.
    //Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    string localFilename = "temp.jpg"; // <-- NOTE IGO to exclusively show instagram
    string localPath = Path.Combine(ExternalStorageDirectory, localFilename);

    File.WriteAllBytes(localPath, bytes); // writes to local storage
    this.Publish(new MaskMessageEvent("Copy ready for Instagram App", false));

    /// See the Apple documentation articles: Previewing and Opening Files and the 
    /// UIDocumentInteractionController Class Reference for more information.
    Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
    {

        this.Publish(new MaskMessageEvent("Launching Instagram App", true));
        Intent shareIntent = new Intent(Intent.ActionSend);
        shareIntent.SetType("image/*");

        Java.IO.File media = new Java.IO.File(ExternalStorageDirectory + Java.IO.File.Separator + localFilename);
        Android.Net.Uri uri = Android.Net.Uri.FromFile(media);

        shareIntent.PutExtra(Intent.ExtraStream, uri); // set uri
        shareIntent.SetPackage("com.instagram.android");
        Forms.Context.StartActivity(shareIntent);
        this.Publish(new MaskMessageEvent("Launching Instagram App", false));

        this.Publish(new InstagramServiceEvent(message, true));
    });

但是现在如果我定位Android 7+,我会收到以下错误

[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] Android.OS.FileUriExposedException: file:///storage/emulated/0/temp.jpg exposed beyond app through ClipData.Item.getUri()
[MonoDroid]   at Java.Interop.JniEnvironment+InstanceMethods.CallNonvirtualVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00089] in <405ad2ab226e4e74ba67db96baf95129>:0 
[MonoDroid]   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0005d] in <405ad2ab226e4e74ba67db96baf95129>:0 
[MonoDroid]   at Android.Content.ContextWrapper.StartActivity (Android.Content.Intent intent) [0x00031] in <476f28c60f03479ab89477af687cdc1a>:0 
[MonoDroid]   at nativeapp.Droid.InstagramService+<>c__DisplayClass6_1.<SendToInstagram>b__1 () [0x0007a] in /Users/rob/Documents/GitHub/social-scheduler/nativeapp/Droid/Services/InstagramService.cs:122 
[MonoDroid]   at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <476f28c60f03479ab89477af687cdc1a>:0 
[MonoDroid]   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00009] in <476f28c60f03479ab89477af687cdc1a>:0 
[MonoDroid]   at (wrapper dynamic-method) System.Object.17(intptr,intptr)
[MonoDroid]   --- End of managed Android.OS.FileUriExposedException stack trace ---
[MonoDroid] android.os.FileUriExposedException: file:///storage/emulated/0/temp.jpg exposed beyond app through ClipData.Item.getUri()
[MonoDroid]     at android.os.StrictMode.onFileUriExposed(StrictMode.java:1960)
[MonoDroid]     at android.net.Uri.checkFileUriExposed(Uri.java:2356)
[MonoDroid]     at android.content.ClipData.prepareToLeaveProcess(ClipData.java:942)
[MonoDroid]     at android.content.Intent.prepareToLeaveProcess(Intent.java:9850)
[MonoDroid]     at android.content.Intent.prepareToLeaveProcess(Intent.java:9835)
[MonoDroid]     at android.app.Instrumentation.execStartActivity(Instrumentation.java:1610)
[MonoDroid]     at android.app.Activity.startActivityForResult(Activity.java:4487)
[MonoDroid]     at android.app.Activity.startActivityForResult(Activity.java:4445)
[MonoDroid]     at android.app.Activity.startActivity(Activity.java:4806)
[MonoDroid]     at android.app.Activity.startActivity(Activity.java:4774)
[MonoDroid]     at mono.java.lang.RunnableImplementor.n_run(Native Method)
[MonoDroid]     at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30)
[MonoDroid]     at android.os.Handler.handleCallback(Handler.java:790)
[MonoDroid]     at android.os.Handler.dispatchMessage(Handler.java:99)
[MonoDroid]     at android.os.Looper.loop(Looper.java:164)
[MonoDroid]     at android.app.ActivityThread.main(ActivityThread.java:6494)
[MonoDroid]     at java.lang.reflect.Method.invoke(Native Method)
[MonoDroid]     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
[MonoDroid]     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
[MonoDroid] 

我已经看到一些使用文件处理程序FileProvider的参考(请参阅ProAndroidDev article ),但我不太明白它是如何工作的,是否使我能够简单地将图像传递给Instagram。它在文章中提到的所有域名让我非常困惑。

有没有更好的方式让我简单地将图像传递给Instagram?在未来我也想考虑视频支持,所以如果可以考虑到这将是伟大的。

现在我已将我的目标Android版本设置为6,以便应用程序继续工作,但我确实希望将目标设置为更现代的东西,这是我唯一的绊脚石。

android xamarin xamarin.forms instagram android-7.0-nougat
1个回答
0
投票

有用的链接是

Android Developer - Secure File Sharing

Pro Android Dev.com - blog

最困难的部分是准确理解放置所有内容的位置,因此我已经包含了完整的上下文,以便让其他人更轻松。

首先是Android Manifest,其中包括App Center Push,但我已经清楚地显示了文件共享部分

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.devology.socialscheduler" android:versionName="1.11.3" android:versionCode="36" android:installLocation="internalOnly">
        <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="28" />
        <application android:label="Social Scheduler App" android:icon="@drawable/icon">

            <!-- App Center PUSH -->
            <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
            <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                    <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                    <category android:name="${applicationId}" />
                </intent-filter>
            </receiver>
            <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_notification" />

            <!-- File Sharing -->
            <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.devology.socialscheduler.fileprovider" android:exported="false" android:grantUriPermissions="true">
                <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_provider_paths" />
            </provider>
        </application>
    </manifest>

文件提供程序指向名为@ xml / file_provider_paths的资源,将它放在正确的位置非常重要...

Where to put file_provider_paths

这是file_provider_paths.xml的内容

<!-- e.g. content://com.devology.socialscheduler.fileprovider/myimages/default_image.jpg -->
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="/"/>
</paths>

然后,我将图像从互联网下载到临时文件中,然后使用文件提供程序创建URL,然后将其传递给Android共享表

    var webClient = new WebClient();
    webClient.DownloadDataCompleted += (s, e) =>
    {
        this.Publish(new MaskMessageEvent("Downloading image from Social Scheduler", false));

        if (e.Error != null)
        {

            this.Publish(new InstagramServiceEvent(message, false));

            this.Publish(
                new ToasterEvent(
                "Oops - " + e.Error.Message));

        }
        else
        {

            this.Publish(new MaskMessageEvent("Copy ready for Instagram App", true));

            var bytes = e.Result; // get the downloaded data

            var context = Android.App.Application.Context;
            AppStorageDirectory = context.FilesDir + Java.IO.File.Separator; //+"images";

            /// You must first save your file in PNG or JPEG (preferred) format and use the filename extension ".ig"
            /// Using the iOS Document Interaction APIs you can trigger the photo to be opened by Instagram. 
            /// The Identifier for our Document Interaction UTI is com.instagram.photo, 
            /// and it conforms to the public/jpeg and public/png UTIs. 
            ///  Alternatively, if you want to show only Instagram in the application list 
            /// (instead of Instagram plus any other public/jpeg-conforming apps) you can specify the 
            /// extension class igo, which is of type com.instagram.exclusivegram.
            //Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            string localFilename = "temp.jpg"; // <-- NOTE IGO to exclusively show instagram
            string localPath = Path.Combine(AppStorageDirectory, localFilename);

            File.WriteAllBytes(localPath, bytes); // writes to local storage
            this.Publish(new MaskMessageEvent("Copy ready for Instagram App", false));

            /// See the Apple documentation articles: Previewing and Opening Files and the 
            /// UIDocumentInteractionController Class Reference for more information.
            Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
            {

                this.Publish(new MaskMessageEvent("Launching Instagram App", true));
                Intent shareIntent = new Intent(Intent.ActionSend);
                shareIntent.SetType("image/*");

                Java.IO.File media = new Java.IO.File(AppStorageDirectory + Java.IO.File.Separator + localFilename);

                var fileUri = FileProvider.GetUriForFile(
                MainActivity.CURRENT_ACTIVITY,
                "com.devology.socialscheduler.fileprovider",
                media);

                //Android.Net.Uri uri = Android.Net.Uri.FromFile(media);

                shareIntent.PutExtra(Intent.ExtraStream, fileUri); // set uri
                shareIntent.SetPackage("com.instagram.android");
                Forms.Context.StartActivity(shareIntent);
                this.Publish(new MaskMessageEvent("Launching Instagram App", false));

                this.Publish(new InstagramServiceEvent(message, true));
            });
        }
    };

    webClient.DownloadDataAsync(new Uri(message.ImageUrl));

请注意,有一些关于使用文件扩展名IGO的旧评论 - 这用于确保只提供Instagram,但似乎在某些时候停止工作。

© www.soinside.com 2019 - 2024. All rights reserved.