Часто разработчики добавляют в приложение возможность отослать письмо другу с ссылкой на приложение. Обычно это возможно сделать штатными средствами конечной ОС. При портировании нашего приложения на Android мне пришлось потратить некоторое время, чтобы добавить эту функциональность. В последний раз я работал с языком Java лет 5 назад, и мне не хотелось лезть в дебри написания Android-плагина для Unity, установки Eclipse, сборки jar-файла, настройки AndroidManifest.xml и тд. Мне удалось это сделать на C#, не написав ни строчки кода на Java (если не считать в комментариях). Хочу поделиться с Вами, как я это сделал, чтобы Вы не тратили свое время. При этом указанный в статье метод можно использовать для вызова любого Java-кода.
Существует очень простой вариант. Если текст письма небольшой, не содержит html-коды, то можно воспользоваться URI-схемой mailto:
Т.е. создается специальная ссылка и открывается с помощью функции Unity Application.OpenURL. Не все почтовые программы адекватно воспринимают такую ссылку, особенно если в тексте есть пробелы. Поэтому приходится воспользоваться WWW.EscapeURL.
Что же делать, если нужно послать письмо, содержащее ссылки, изображения и т.д.?
Это можно сделать с помощью встроенной почтовой программы Android. Для этого нужно писать следующий Java-код:
Его можно найти в многочисленных примерах в сети. На Хабре была статья о том, как это сделать на Andoird. Если интересно, что делает этот код, почитайте ее.
Далее, чтобы вызвать этот код из Unity, нужно собрать jar-файл, вызвать Java-функцию из C#-скрипта и тд. Но можно обойтись без всего этого. Нам помогут вспомогательные классы Unity AndroidJavaClass и AndroidJavaObject. Это очень полезные инструменты. С их помощью можно получить доступ к любому Java-классу и любому Java-объекту, соответственно, а также создавать Java-объекты, получить доступ к методам класса, статическим методам и данным и тд.
Я переписал его на C#, используя указанные выше классы:
Переменная intentClass предоставляет доступ к Java-классу android.content.Intent, чем я и воспользовался для получения доступа к константам типа Intent.EXTRA_TEXT используя функцию GetStatic:
Переменная intentObject — ссылка на созданный объект Java-класса android.content.Intent. Как видите, создавать объекты Java-класса очень легко:
Первый параметр конструктора класса AndroidJavaObject — имя Java-класса, остальные параметры — параметры конструктора уже самого Java-класса.
Не стоит путать AndroidJavaObject c AndroidJavaClass, используйте каждый по назначению. Эти классы настолько похожи визуально (AndroidJavaClass даже наследуется от AndroidJavaObject), что в одном месте я использовал AndroidJavaClass вместо AndroidJavaObject и не заметил этого. Печально, но на исправление этой маленькой детали ушло время.
Директива using используется для своевременного «освобождения» Java-объектов. Об этом хорошо написано в Best practice when using Java plugins with Unity.
Доступ к методам класса осуществаляется через функцию Call, при этом если метод возвращает результат, то используется обобщенный вариант функции, для указания типа возвращаемого результата:
Не забывайте об этом: даже если вам не нужен возвращаемый результат, тип результата нужно все равно указывать, иначе получите неправильную сигнатуру метода и он не будет найден, или, что еще хуже, вы нехотя вызовете похожий метод (если он есть), не возвращающий результат, и не сразу заметите ошибку.
В конце получаем текущий контекст (currentActivity и будет им) и инициируем отсылку с помощью созданного объекта intentObject:
Вот и все.
Похожим образом можно переписать практически любой Java-код. Рекомендую этот метод в том случае, если код небольшой и не хочется писать плагин. В ином случае, конечно, получается очень громоздкий код, непонятный несведущему человеку.
Готов выслушать вопросы и предложения;)
Возможно, кому-то будет интересно почитать мои предыдущие статьи:
Удачи Вам в Ваших разработках!
Простой вариант
Существует очень простой вариант. Если текст письма небольшой, не содержит html-коды, то можно воспользоваться URI-схемой mailto:
string url = string.Format("mailto:{0}?subject={1}&body={2}", to, WWW.EscapeURL(subject), WWW.EscapeURL(body));
Application.OpenURL(url);
Т.е. создается специальная ссылка и открывается с помощью функции Unity Application.OpenURL. Не все почтовые программы адекватно воспринимают такую ссылку, особенно если в тексте есть пробелы. Поэтому приходится воспользоваться WWW.EscapeURL.
Что же делать, если нужно послать письмо, содержащее ссылки, изображения и т.д.?
Вариант с HTML
Это можно сделать с помощью встроенной почтовой программы Android. Для этого нужно писать следующий Java-код:
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);
Его можно найти в многочисленных примерах в сети. На Хабре была статья о том, как это сделать на Andoird. Если интересно, что делает этот код, почитайте ее.
Далее, чтобы вызвать этот код из Unity, нужно собрать jar-файл, вызвать Java-функцию из C#-скрипта и тд. Но можно обойтись без всего этого. Нам помогут вспомогательные классы Unity AndroidJavaClass и AndroidJavaObject. Это очень полезные инструменты. С их помощью можно получить доступ к любому Java-классу и любому Java-объекту, соответственно, а также создавать Java-объекты, получить доступ к методам класса, статическим методам и данным и тд.
Я переписал его на C#, используя указанные выше классы:
/// <summary>
/// Sends mail using default mail application.
/// </summary>
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<string>("ACTION_SEND")))
{
// Setting text type
if (isHTML)
// intent.setType("text/html");
intentObject.Call<AndroidJavaObject>("setType", "text/html");
else
// intent.setType("message/rfc822");
intentObject.Call<AndroidJavaObject>("setType", "message/rfc822");
// intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("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<AndroidJavaObject>("fromHtml", body);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), htmlBody);
}
}
else
{
// intent.putExtra(Intent.EXTRA_TEXT, body);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), body);
}
// startActivity(intent);
using (var unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity"))
{
currentActivity.Call("startActivity", intentObject);
}
}
}
}
}
Переменная intentClass предоставляет доступ к Java-классу android.content.Intent, чем я и воспользовался для получения доступа к константам типа Intent.EXTRA_TEXT используя функцию GetStatic:
intentClass.GetStatic<string>("EXTRA_TEXT")
Переменная intentObject — ссылка на созданный объект Java-класса android.content.Intent. Как видите, создавать объекты Java-класса очень легко:
var intentObject = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic<string>("ACTION_SEND"))
Первый параметр конструктора класса AndroidJavaObject — имя Java-класса, остальные параметры — параметры конструктора уже самого Java-класса.
Не стоит путать AndroidJavaObject c AndroidJavaClass, используйте каждый по назначению. Эти классы настолько похожи визуально (AndroidJavaClass даже наследуется от AndroidJavaObject), что в одном месте я использовал AndroidJavaClass вместо AndroidJavaObject и не заметил этого. Печально, но на исправление этой маленькой детали ушло время.
Директива using используется для своевременного «освобождения» Java-объектов. Об этом хорошо написано в Best practice when using Java plugins with Unity.
Доступ к методам класса осуществаляется через функцию Call, при этом если метод возвращает результат, то используется обобщенный вариант функции, для указания типа возвращаемого результата:
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), body);
Не забывайте об этом: даже если вам не нужен возвращаемый результат, тип результата нужно все равно указывать, иначе получите неправильную сигнатуру метода и он не будет найден, или, что еще хуже, вы нехотя вызовете похожий метод (если он есть), не возвращающий результат, и не сразу заметите ошибку.
В конце получаем текущий контекст (currentActivity и будет им) и инициируем отсылку с помощью созданного объекта intentObject:
using (var unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity"))
{
currentActivity.Call("startActivity", intentObject);
}
}
Вот и все.
Похожим образом можно переписать практически любой Java-код. Рекомендую этот метод в том случае, если код небольшой и не хочется писать плагин. В ином случае, конечно, получается очень громоздкий код, непонятный несведущему человеку.
Готов выслушать вопросы и предложения;)
Возможно, кому-то будет интересно почитать мои предыдущие статьи:
- Игра за два дня
- Как сделать промо-ролик игры малыми силами — Статья написана Алексеем Луниным — type_2.
- 2d на Unity3d
- Принципы минимализма при разработке игр для мобильных платформ
- Оптимизация 2d-приложений для мобильных устройств в Unity3d
Удачи Вам в Ваших разработках!