- Home
- >> Nerd Digest
- >> Unity3D
-
How to Share Image & Link on Twitter through Unity iOS App
about 7 years ago
When it comes to Game Engines and Game Development, the technology name unity comes at top as it is not only most popular and powerful game engine which has a great visual editor for developing the games for iOS and Android but also have a lots of functionality, features, and community for issue handling with good pricing options. Without a doubt, Unity is considered to be the best for building iOS and Android games and app easily.
Today in this tutorial, I am sharing a topic related to the iOS app with the help of which one can easily share an image or a link to twitter from the app. Whereas sharing an image is not a big task but encase of iOS, the user has to upload an image or write an image on device path first and then read an image from that path, as resources folder doesn't exist in iOS. So with the help of below code one can easily read and write an image to the device path.
Lets see how:
First create an app on Twitter and save app's consumer key, secret key, media URL and Tweet URL.
Then In order to share on Twitter, user have to Login on Twitter . So let's Login user using below mentioned code.
Now, Let's create three UI buttons.
1. Twitter Login Button //call TwitterLogin on click
2. Submit Pin Button //call SubmitPin() on click
3. Twitter Share Button //call TwitterShare() on click.
and create one InputField to enter PIN that you receive after calling TwittterLogin() function.
1. InputFieldPin
In start activate Twitter Login button only. Then on success disable login button and enable inputfield and submit button. Then on successful Login enable Share button and disable all other buttons.
Now create two scripts :-
1. TwitterHandller and
2. Twitter#TwitterHandller.cs
using UnityEngine; using UnityEngine.UI; using System.Collections; using System; using System.IO; using System.Net; using System.Xml; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Globalization; using System.Linq; using System.Security.Cryptography; using UnityEngine; using SimpleJSON; using System.Runtime.InteropServices; public class TwitterHandller: MonoBehaviour { Twitter.RequestTokenResponse m_RequestTokenResponse; Twitter.AccessTokenResponse m_AccessTokenResponse; public string CONSUMER_KEY;//Put oun consumer key here public string CONSUMER_SECRET;//Put own consumer secret here // Use this for initialization void Start() { LoadUserTwitterInfo(); } void LoadUserTwitterInfo() { m_AccessTokenResponse = new Twitter.AccessTokenResponse(); m_AccessTokenResponse.UserId = PlayerPrefs.GetString(PLAYER_PREFS_TWITTER_USER_ID); m_AccessTokenResponse.ScreenName = PlayerPrefs.GetStrin(PLAYER_PREFS_TWITTER_USER_SCREEN_NAME); m_AccessTokenResponse.Token = PlayerPrefs.GetString(PLAYER_PREFS_TWITTER_USER_TOKEN); m_AccessTokenResponse.TokenSecret = PlayerPrefs.GetString(PLAYER_PREFS_TWITTER_USER_TOKEN_SECRET); //Debug.Log ("ID"+m_AccessTokenResponse.UserId ); // Debug.Log ("Name"+m_AccessTokenResponse.ScreenName ); // Debug.Log ("Token"+m_AccessTokenResponse.Token ); // Debug.Log ("Token Secret"+m_AccessTokenResponse.TokenSecret ); if (!string.IsNullOrEmpty(m_AccessTokenResponse.Token) && !string.IsNullOrEmpty (m_AccessTokenResponse.ScreenName) && !string.IsNullOrEmpty(m_AccessTokenResponse.Token) && !string.IsNullOrEmpty(m_AccessTokenResponse.TokenSecret)) { string log = "LoadTwitterUserInfo - succeeded"; log += "\n UserId : " + m_AccessTokenResponse.UserId; log += "\n ScreenName : " + m_AccessTokenResponse.ScreenName; log += "\n Token : " + m_AccessTokenResponse.Token; log += "\n TokenSecret : " + m_AccessTokenResponse.TokenSecret; print(log); } } public void TwitterLogin() { //Calling GetRequestToken function of Twitter API use your own consumer key and consumer secret. StartCoroutine(Twitter.API.GetRequestToken(CONSUMER_KEY, CONSUMER_SECRET, new Twitter.RequestTokenCallback(this.OnRequestTokenCallback))); } public void SubmitPin() { StartCoroutine(Twitter.API.GetAccessToken(CONSUMER_KEY, CONSUMER_SECRET, m_RequestTokenResponse.Token, m_PIN, new Twitter.AccessTokenCallback(this.OnAccessTokenCallback))); } public void TwitterShare() { //put url of the image that you want to share string url="https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/8e/d7/e9 /8ed7e940-9fda-d1ca-995e-d4e2086a438c/pr_source.jpg/150x150bb.jpg"; string savePath = Path.Combine(Application.persistentDataPath, "data"); //downloading image from url and saving to path downloadImage(url, savePath); //loading image from the path in byte array byte[] imageBytes = loadImage(savePath); //Calling PostTweet function of Twitter API StartCoroutine(Twitter.API.PostTweet(imageBytes,m_Tweet,CONSUMER_KEY,CONSUMER_SECRET, m_AccessTokenResponse, new Twitter.PostTweetCallback(this.OnPostTweet))); } }
#Twitter.cs
using System; using System.IO; using System.Net; using System.Xml; using System.Collections.Generic; using System.Text; using System.Collections; using System.Text.RegularExpressions; using System.Globalization; using System.Linq; using System.Security.Cryptography; using UnityEngine; using SimpleJSON; using System.IO; using System.Runtime.InteropServices; namespace Twitter { public class RequestTokenResponse { public string Token { get; set; } public string TokenSecret { get; set; } } public class AccessTokenResponse { public string Token { get; set; } public string TokenSecret { get; set; } public string UserId { get; set; } public string ScreenName { get; set; } } public delegate void RequestTokenCallback(bool success, RequestTokenResponse response); public delegate void AccessTokenCallback(bool success, AccessTokenResponse response); public delegate void PostTweetCallback(bool success); public delegate void GetTimelineCallback(bool success); public class API { #region OAuth Token Methods // 1. Get Request-Token From Twitter // 2. Get PIN from User // 3. Get Access-Token from Twitter // 4. Use Accss-Token for APIs requriring OAuth // Accss-Token will be always valid until the user revokes the access to your application. // Twitter APIs for OAuth process private static readonly string RequestTokenURL = "https://api.twitter.com/oauth/request_token"; private static readonly string AuthorizationURL = "https://api.twitter.com/oauth/authenticate?oauth_token={0}"; private static readonly string AccessTokenURL = "https://api.twitter.com/oauth/access_token"; public static IEnumerator GetRequestToken(string consumerKey, string consumerSecret, RequestTokenCallback callback) { WWW web = WWWRequestToken(consumerKey, consumerSecret); yield return web; if (!string.IsNullOrEmpty(web.error)) { Debug.Log(string.Format("GetRequestToken - failed. error : {0}", web.error)); callback(false, null); } else { RequestTokenResponse response = new RequestTokenResponse { Token = Regex.Match(web.text, @"oauth_token=([^&]+)").Groups[1].Value, TokenSecret = Regex.Match(web.text, @"oauth_token_secret=([^&]+)").Groups[1].Value, }; if (!string.IsNullOrEmpty(response.Token) && !string.IsNullOrEmpty(response.TokenSecret)) { callback(true, response); } else { Debug.Log(string.Format("GetRequestToken - failed. response : {0}", web.text)); callback(false, null); } } } public static void OpenAuthorizationPage(string requestToken) { Application.OpenURL(string.Format(AuthorizationURL, requestToken)); } public static IEnumerator GetAccessToken(string consumerKey, string consumerSecret, string requestToken, string pin, AccessTokenCallback callback) { Debug.Log ("GetAccessToken"); WWW web = WWWAccessToken(consumerKey, consumerSecret, requestToken, pin); yield return web; if (!string.IsNullOrEmpty(web.error)) { Debug.Log(string.Format("GetAccessToken - failed. error : {0}", web.error)); callback(false, null); } else { AccessTokenResponse response = new AccessTokenResponse { Token = Regex.Match(web.text, @"oauth_token=([^&]+)").Groups[1].Value, TokenSecret = Regex.Match(web.text, @"oauth_token_secret=([^&]+)").Groups[1].Value, UserId = Regex.Match(web.text, @"user_id=([^&]+)").Groups[1].Value, ScreenName = Regex.Match(web.text, @"screen_name=([^&]+)").Groups[1].Value }; if (!string.IsNullOrEmpty(response.Token) && !string.IsNullOrEmpty(response.TokenSecret) && !string.IsNullOrEmpty(response.UserId) && !string.IsNullOrEmpty(response.ScreenName)) { callback(true, response); } else { Debug.Log(string.Format("GetAccessToken - failed. response : {0}", web.text)); callback(false, null); } } } private static WWW WWWRequestToken(string consumerKey, string consumerSecret) { // Add data to the form to post. WWWForm form = new WWWForm(); form.AddField("oauth_callback", "oob"); // HTTP header Dictionary<string, string> parameters = new Dictionary<string, string>(); AddDefaultOAuthParams(parameters, consumerKey, consumerSecret); parameters.Add("oauth_callback", "oob"); Dictionary<string, string> headers = new Dictionary<string, string>(); headers["Authorization"] = GetFinalOAuthHeader("POST", RequestTokenURL, parameters); return new WWW(RequestTokenURL, form.data, headers); } private static WWW WWWAccessToken(string consumerKey, string consumerSecret, string requestToken, string pin) { // Need to fill body since Unity doesn't like an empty request body. byte[] dummmy = new byte[1]; dummmy[0] = 0; // HTTP header Dictionary<string, string> headers = new Dictionary<string, string>(); Dictionary<string, string> parameters = new Dictionary<string, string>(); AddDefaultOAuthParams(parameters, consumerKey, consumerSecret); parameters.Add("oauth_token", requestToken); parameters.Add("oauth_verifier", pin); headers["Authorization"] = GetFinalOAuthHeader("POST", AccessTokenURL, parameters); return new WWW(AccessTokenURL, dummmy, headers); } private static string GetHeaderWithAccessToken(string httpRequestType, string apiURL, string consumerKey, string consumerSecret, AccessTokenResponse response, Dictionary<string, string> parameters) { AddDefaultOAuthParams(parameters, consumerKey, consumerSecret); parameters.Add("oauth_token", response.Token); parameters.Add("oauth_token_secret", response.TokenSecret); return GetFinalOAuthHeader(httpRequestType, apiURL, parameters); } #endregion #region Twitter API Methods private const string PostTweetURL = "https://api.twitter.com/1.1/statuses/update.json"; private const string GetTimelineURL = "https://api.twitter.com/1.1/statuses/home_timeline.json"; private const string UploadMediaURL = "https://upload.twitter.com/1.1/media/upload.json"; public static IEnumerator PostTweet(byte[] imageBytes, string text, string consumerKey, string consumerSecret, AccessTokenResponse response, PostTweetCallback callback) { Dictionary<string, string> mediaParameters = new Dictionary<string, string>(); string encoded64ImageData = Convert.ToBase64String(imageBytes); mediaParameters.Add("media_data", encoded64ImageData); // Add data to the form to post. WWWForm mediaForm = new WWWForm(); mediaForm.AddField("media_data", encoded64ImageData); // HTTP header Dictionary<string, string> mediaHeaders = new Dictionary<string, string>(); string auth = GetHeaderWithAccessToken("POST", UploadMediaURL, consumerKey, consumerSecret, response, mediaParameters); mediaHeaders.Add("Authorization", auth); mediaHeaders.Add("Content-Transfer-Encoding", "base64"); WWW mw = new WWW(UploadMediaURL, mediaForm.data, mediaHeaders); yield return mw; string mID = Regex.Match(mw.text, @"(\Dmedia_id\D\W)(\d*)").Groups[2].Value; Debug.Log("response from media request : " + mw.text); Debug.Log("mID = " + mID); if (!string.IsNullOrEmpty(mw.error)) { Debug.Log(string.Format("PostTweet - failed. {0}\n{1}", mw.error, mw.text)); callback(false); } else { string error = Regex.Match(mw.text, @"<error>([^&]+)</error>").Groups[1].Value; if (!string.IsNullOrEmpty(error)) { Debug.Log(string.Format("PostTweet - failed. {0}", error)); callback(false); } else { callback(true); } } string url="https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/8e/d7/e9/8ed7e940-9fda-d1ca-995e-d4e2086a438c/pr_source.jpg/150x150bb.jpg"; Dictionary<string, string> parameters = new Dictionary<string, string>(); parameters.Add("status", url); parameters.Add("media_ids", mID); //parameters.Add("url", url); // Add data to the form to post. WWWForm form = new WWWForm(); form.AddField("status", url); form.AddField("media_ids", mID); //form.AddField("url", url); // HTTP header var headers = new Dictionary<string, string>(); headers["Authorization"] = GetHeaderWithAccessToken("POST", PostTweetURL, consumerKey, consumerSecret, response, parameters); WWW web = new WWW(PostTweetURL, form.data, headers); yield return web; if (!string.IsNullOrEmpty(web.error)) { Debug.Log(string.Format("PostTweet - failed. {0}\n{1}", web.error, web.text)); callback(false); } else { string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value; if (!string.IsNullOrEmpty(error)) { Debug.Log(string.Format("PostTweet - failed. {0}", error)); callback(false); } else { callback(true); } } } #endregion #region OAuth Help Methods private static readonly string[] OAuthParametersToIncludeInHeader = new[] { "oauth_version", "oauth_nonce", "oauth_timestamp", "oauth_signature_method", "oauth_consumer_key", "oauth_token", "oauth_verifier" // Leave signature omitted from the list, it is added manually // "oauth_signature", }; private static readonly string[] SecretParameters = new[] { "oauth_consumer_secret", "oauth_token_secret", "oauth_signature" }; private static void AddDefaultOAuthParams(Dictionary<string, string> parameters, string consumerKey, string consumerSecret) { parameters.Add("oauth_version", "1.0"); parameters.Add("oauth_nonce", GenerateNonce()); parameters.Add("oauth_timestamp", GenerateTimeStamp()); parameters.Add("oauth_signature_method", "HMAC-SHA1"); parameters.Add("oauth_consumer_key", consumerKey); parameters.Add("oauth_consumer_secret", consumerSecret); } private static string GetFinalOAuthHeader(string HTTPRequestType, string URL, Dictionary<string, string> parameters) { // Add the signature to the oauth parameters string signature = GenerateSignature(HTTPRequestType, URL, parameters); parameters.Add("oauth_signature", signature); StringBuilder authHeaderBuilder = new StringBuilder(); authHeaderBuilder.AppendFormat("OAuth realm=\"{0}\"", "Twitter API"); var sortedParameters = from p in parameters where OAuthParametersToIncludeInHeader.Contains(p.Key) orderby p.Key, UrlEncode(p.Value) select p; foreach (var item in sortedParameters) { authHeaderBuilder.AppendFormat(",{0}=\"{1}\"", UrlEncode(item.Key), UrlEncode(item.Value)); } authHeaderBuilder.AppendFormat(",oauth_signature=\"{0}\"", UrlEncode(parameters["oauth_signature"])); return authHeaderBuilder.ToString(); } private static string GenerateSignature(string httpMethod, string url, Dictionary<string, string> parameters) { var nonSecretParameters = (from p in parameters where !SecretParameters.Contains(p.Key) select p); // Create the base string. This is the string that will be hashed for the signature. string signatureBaseString = string.Format(CultureInfo.InvariantCulture, "{0}&{1}&{2}", httpMethod, UrlEncode(NormalizeUrl(new Uri(url))), UrlEncode(nonSecretParameters)); // Create our hash key (you might say this is a password) string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode(parameters["oauth_consumer_secret"]), parameters.ContainsKey("oauth_token_secret") ? UrlEncode(parameters["oauth_token_secret"]) : string.Empty); // Generate the hash HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(key)); byte[] signatureBytes = hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(signatureBaseString)); return Convert.ToBase64String(signatureBytes); } private static string GenerateTimeStamp() { // Default implementation of UNIX time of the current UTC time TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds, CultureInfo.CurrentCulture).ToString(CultureInfo.CurrentCulture); } private static string GenerateNonce() { // Just a simple implementation of a random number between 123400 and 9999999 return new System.Random().Next(123400, int.MaxValue).ToString("X", CultureInfo.InvariantCulture); } private static string NormalizeUrl(Uri url) { string normalizedUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host); if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) { normalizedUrl += ":" + url.Port; } normalizedUrl += url.AbsolutePath; return normalizedUrl; } private static string UrlEncode(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } value = Uri.EscapeDataString(value); // UrlEncode escapes with lowercase characters (e.g. %2f) but oAuth needs %2F value = Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper()); // these characters are not escaped by UrlEncode() but needed to be escaped value = value .Replace("(", "%28") .Replace(")", "%29") .Replace("$", "%24") .Replace("!", "%21") .Replace("*", "%2A") .Replace("'", "%27"); // these characters are escaped by UrlEncode() but will fail if unescaped! value = value.Replace("%7E", "~"); return value; } private static string UrlEncode(IEnumerable<KeyValuePair<string, string>> parameters) { StringBuilder parameterString = new StringBuilder(); var paramsSorted = from p in parameters orderby p.Key, p.Value select p; foreach (var item in paramsSorted) { if (parameterString.Length > 0) { parameterString.Append("&"); } parameterString.Append( string.Format( CultureInfo.InvariantCulture, "{0}={1}", UrlEncode(item.Key), UrlEncode(item.Value))); } return UrlEncode(parameterString.ToString()); } #endregion } }
Now, we have our scripts ready. Let's simply call TwitterLogin() function of "TwitterHandller" script and TwitterShare() function of "TwitterHandller" script on button click. On successful share you got post succeed debug.
That's it, for any queries or feedback, feel free to write in comment section below!
0 Comment(s)