How to send email from an Android device from a Unity application without writing a single line of Java code

    Often, developers add to the application the ability to send a letter to a friend with a link to the application. Usually this can be done using regular means of the final OS. When porting our application to Android, I had to spend some time to add this functionality. The last time I worked with the Java language about 5 years ago, and I did not want to get into the jungle of writing an Android plug-in for Unity, installing Eclipse, building a jar file, setting AndroidManifest.xml , etc. I managed to do this in C # without writing a single line of code in Java (except for in the comments). I want to share with you how I did this so that you do not waste your time. At the same time, the method specified in the article can be used to call any Java code.


    Simple option


    There is a very simple option. If the text of the letter is small, does not contain html codes, then you can use the mailto URI scheme :
    string url = string.Format("mailto:{0}?subject={1}&body={2}", to, WWW.EscapeURL(subject), WWW.EscapeURL(body));
    Application.OpenURL(url);
    

    Those. a special link is created and opened using the Unity Application.OpenURL function . Not all email programs adequately perceive such a link, especially if there are spaces in the text. Therefore, you have to use WWW.EscapeURL .
    What to do if you need to send a letter containing links, images, etc.?

    HTML option


    This can be done using the built-in Android mail program. To do this, write the following Java code:
    intent = new Intent(Intent.ACTION_SEND);
    if (isHTML)
      intent.setType("text/html");
    else
      intent.setType("message/rfc822");
    intent.putExtra(Intent.EXTRA_SUBJECT, subject);
    if (isHTML)
      intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(body));
    else
      intent.putExtra(Intent.EXTRA_TEXT, body);
    startActivity(intent);
    

    It can be found in numerous examples on the net. There was an article on Habr on how to do this on Andoird . If you're interested in what this code does, read it.

    Next, to call this code from Unity, you need to collect the jar file, call the Java function from a C # script, and so on. But you can do without all this. Unity helper classes AndroidJavaClass and AndroidJavaObject will help us . These are very useful tools. With their help, you can access any Java class and any Java object, respectively, as well as create Java objects, access class methods, static methods and data, and so on. I rewrote it in C # using the above classes:


    /// 
    /// Sends mail using default mail application.
    /// 
    private static void SendMail(string subject, string body, bool isHTML)
    {
      using (var intentClass = new AndroidJavaClass("android.content.Intent"))
      {
        // intent = new Intent(Intent.ACTION_SEND);
        using (var intentObject = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic("ACTION_SEND")))
        {
          // Setting text type
          if (isHTML)
            // intent.setType("text/html");
            intentObject.Call("setType", "text/html");
          else
            // intent.setType("message/rfc822");
            intentObject.Call("setType", "message/rfc822");
          // intent.putExtra(Intent.EXTRA_SUBJECT, subject);
          intentObject.Call("putExtra", intentClass.GetStatic("EXTRA_SUBJECT"), subject);
          // Setting body
          if (isHTML)
          {
            // intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(body));
            using (var html = new AndroidJavaClass("android.text.Html"))
            {
              var htmlBody = html.CallStatic("fromHtml", body);
              intentObject.Call("putExtra", intentClass.GetStatic("EXTRA_TEXT"), htmlBody);
            }
          }
          else
          {
            // intent.putExtra(Intent.EXTRA_TEXT, body);
            intentObject.Call("putExtra", intentClass.GetStatic("EXTRA_TEXT"), body);
          }
          // startActivity(intent);
          using (var unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
          {
            using (var currentActivity = unity.GetStatic("currentActivity"))
            {
              currentActivity.Call("startActivity", intentObject);
            }
          }
        }
      }
    }
    

    The intentClass variable provides access to the android.content.Intent Java class , which I used to access constants of the Intent.EXTRA_TEXT type using the GetStatic function :
    intentClass.GetStatic("EXTRA_TEXT")
    

    The intentObject variable is a reference to the created object of the Java class android.content.Intent . As you can see, creating Java class objects is very easy:
    var intentObject = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic("ACTION_SEND"))
    

    The first parameter of the constructor of the AndroidJavaObject class is the name of the Java class, the remaining parameters are the parameters of the constructor of the Java class itself.

    Do not confuse AndroidJavaObject with AndroidJavaClass , use each for its intended purpose. These classes are so similar visually ( AndroidJavaClass is even inherited from AndroidJavaObject ) that in one place I used AndroidJavaClass instead of AndroidJavaObject and did not notice it. Sadly, it took time to fix this small detail.

    The using directive is used to timely "free" Java objects. This is well written inBest practice when using Java plugins with Unity .
    Access to the class methods is carried out through the Call function , and if the method returns a result, then a generalized version of the function is used to indicate the type of the returned result:
    intentObject.Call("putExtra", intentClass.GetStatic("EXTRA_TEXT"), body);
    

    Do not forget about this: even if you do not need the returned result, you still need to indicate the type of the result, otherwise you will get the wrong method signature and it will not be found, or, even worse, you will reluctantly call a similar method (if any) that does not return result, and don’t immediately notice the error.

    At the end, we get the current context ( currentActivity will be it) and initiate the sending using the intentObject created :
    using (var unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
    {
      using (var currentActivity = unity.GetStatic("currentActivity"))
      {
        currentActivity.Call("startActivity", intentObject);
      }
    }
    

    That's all.
    In a similar way, almost any Java code can be rewritten. I recommend this method if the code is small and you do not want to write a plugin. Otherwise, of course, it turns out a very cumbersome code, incomprehensible to an ignorant person.

    Ready to listen to questions and suggestions;)

    Perhaps someone will be interested to read my previous articles:


    Good luck in your development!

    Also popular now: