2

I've captured screenshot in my game when player dies. I've following code to capture screen shot.

RenderTexture rt = new RenderTexture (800, 600, 24);
    MainCamera.targetTexture = rt;
    Texture2D texture = new Texture2D (800, 600, TextureFormat.RGB24, false);
    MainCamera.Render ();
    RenderTexture.active = rt;
    texture.ReadPixels (new Rect (0, 0, 800, 600), 0, 0);
    MainCamera.targetTexture = null;
    RenderTexture.active = null;
    Destroy (rt);
    byte[] bytes = texture.EncodeToPNG ();
    Directory.CreateDirectory (Application.persistentDataPath + "/GameOverScreenShot");
    File.WriteAllBytes (Application.persistentDataPath + "/GameOverScreenShot" + "/DiedScreenShot.png", bytes);

I am getting saved screenshot using following code.

byte[] bytes = File.ReadAllBytes (Application.persistentDataPath +"/GameOverScreenShot" + "/BirdDiedScreenShot.png");

Texture2D texture = new Texture2D (800, 600, TextureFormat.RGB24, false);
RectOffset tempOffset = new RectOffset (5, 5, 5, 5);
texture.filterMode = FilterMode.Trilinear;
texture.LoadImage (bytes);
Sprite sprite = Sprite.Create (texture, new Rect (0, 0, 800, 400), new Vector2 (0.5f, 0.0f), 2.0f);
ScreenShot_Image.GetComponent<Image> ().sprite = sprite;

Now, I want to share this screenshot on android application. As per my research i have got following code for that, but it is returning blank image.

//instantiate the class Intent
AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent");

//instantiate the object Intent
AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent");

//call setAction setting ACTION_SEND as parameter
intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND"));

//instantiate the class Uri
AndroidJavaClass uriClass = new AndroidJavaClass("android.net.Uri");

//instantiate the object Uri with the parse of the url's file
string destination = Application.persistentDataPath + "/GameOverScreenShot" + "/DiedScreenShot.png";
AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject>("parse","file://"+destination);

//call putExtra with the uri object of the file
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_STREAM"), uriObject);

//set the type of file
intentObject.Call<AndroidJavaObject>("setType", "image/*");

//instantiate the class UnityPlayer
AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer");

//instantiate the object currentActivity
AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");

//call the activity with our Intent
currentActivity.Call("startActivity", intentObject);

What should I change in this?? Please help, Advance Thanks

Piina Kansara
  • 37
  • 2
  • 5

2 Answers2

4

Simply call takeScreenShotAndShare() to take Screen Shot and share it. If you already have the image you want to share, just call StartCoroutine(shareScreenshot(path)); and pass in the path/location of the image. This only supports png images. To share jpeg, change

intentObject.Call<AndroidJavaObject>("setType", "image/png");

to

intentObject.Call<AndroidJavaObject>("setType", "image/jpeg");

The whole code:

void takeScreenShotAndShare()
{
    StartCoroutine(takeScreenshotAndSave());
}

private IEnumerator takeScreenshotAndSave()
{
    string path = "";
    yield return new WaitForEndOfFrame();

    Texture2D screenImage = new Texture2D(Screen.width, Screen.height);

    //Get Image from screen
    screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
    screenImage.Apply();

    //Convert to png
    byte[] imageBytes = screenImage.EncodeToPNG();


    System.IO.Directory.CreateDirectory(Application.persistentDataPath + "/GameOverScreenShot");
    path = Application.persistentDataPath + "/GameOverScreenShot" + "/DiedScreenShot.png";
    System.IO.File.WriteAllBytes(path, imageBytes);

    StartCoroutine(shareScreenshot(path));
}

private IEnumerator shareScreenshot(string destination)
{
    string ShareSubject = "Picture Share";
    string shareLink = "Test Link" + "\nhttp://stackoverflow.com/questions/36512784/share-image-on-android-application-from-unity-game";
    string textToShare = "Text To share";

    Debug.Log(destination);


    if (!Application.isEditor)
    {

        AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent");
        AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent");
        intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND"));
        AndroidJavaClass uriClass = new AndroidJavaClass("android.net.Uri");
        AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject>("parse", "file://" + destination);

        intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_STREAM"), uriObject);
        intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), textToShare + shareLink);
        intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_SUBJECT"), ShareSubject);
        intentObject.Call<AndroidJavaObject>("setType", "image/png");
        AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");
        currentActivity.Call("startActivity", intentObject);
    }
    yield return null;
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Programmer
  • 121,791
  • 22
  • 236
  • 328
0

In Android 8+, this method does not work. We need to use FileProvider.

Google changed the sharing way using FileProvider to make it more secure, we can not share the file object directly to any other Application. We need to use the FileProvider and grant read URI permission to make it accessible for any other app.

  • Create a New Project in Android Studio, and select the template as Android Library
  • Create a new XML resource file with name "provider_paths.xml" in our library. Add this code in XML file:
 <?xml version="1.0" encoding="utf-8"? >
 <paths xmlns:android="http://schemas.android.com/apk/res/android" >
     <external-path name="external_files" path="."/ >
 </paths>
  • Define Provider in the manifest.xml file of the library.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jk.pluginexample">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
    </application>
</manifest>
  • Export it as an Android archive file (.aar) from Android Studio.

  • Finally add C# code in your Unity Project:

#if UNITY_ANDROID
    public IEnumerator ShareScreenshotInAnroid()    // New Sharing, using FileProvider that works in Android 7+
    {
        isProcessing = true;
        // wait for graphics to render
        yield return new WaitForEndOfFrame();

        string screenShotPath = Application.persistentDataPath + "/" + screenshotName;
        ScreenCapture.CaptureScreenshot(screenshotName, 1);
        yield return new WaitForSeconds(0.5f);

        if (!Application.isEditor)
        {
            //current activity context
            AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");

            //Create intent for action send
            AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent");
            AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent");
            intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND"));

            //old code which is not allowed in Android 8 or above
            //create image URI to add it to the intent
            //AndroidJavaClass uriClass = new AndroidJavaClass ("android.net.Uri");
            //AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject> ("parse", "file://" + screenShotPath);

            //create file object of the screenshot captured
            AndroidJavaObject fileObject = new AndroidJavaObject("java.io.File", screenShotPath);

            //create FileProvider class object
            AndroidJavaClass fileProviderClass = new AndroidJavaClass("androidx.core.content.FileProvider");

            object[] providerParams = new object[3];
            providerParams[0] = currentActivity;
            providerParams[1] = "com.YOURCOMPANY.YOURPACKAGENAME.provider";
            providerParams[2] = fileObject;

            //instead of parsing the uri, will get the uri from file using FileProvider
            AndroidJavaObject uriObject = fileProviderClass.CallStatic<AndroidJavaObject>("getUriForFile", providerParams);

            //put image and string extra
            intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_STREAM"), uriObject);
            intentObject.Call<AndroidJavaObject>("setType", "image/png");
            intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_SUBJECT"), shareSubject);
            intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), shareMessage);

            //additionally grant permission to read the uri
            intentObject.Call<AndroidJavaObject>("addFlags", intentClass.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION"));

            AndroidJavaObject chooser = intentClass.CallStatic<AndroidJavaObject>("createChooser", intentObject, "Share your high score");
            currentActivity.Call("startActivity", chooser);
        }

        yield return new WaitUntil(() => isFocus);
        isProcessing = false;
    }
#endif

I have used androidx.core.content.FileProvider, as all libraries are migrating to AndroidX. You can also use android.support.v4.content.FileProvider.

The full Post by Suneet Agrawal is here. I have only provided the key steps.

Junaid Pathan
  • 3,850
  • 1
  • 25
  • 47