If you’ve been looking for a way to use any Twitter features in your Appcelerator application, check out social_plus.js on GitHub (from Aaron Sanders – Great resource for Appcelerator, Ionic Framework and many other frameworks and just code in general).
You might notice a minor inconvenience with getting this to work on Android versions > v3.3. Actually it’s an issue with Chrome not allowing evalJS() to get the OAuth PIN silently from Twitter during the OAuth authentication procedures – You’ll notice an additional webpage is loaded with a PIN… So what are you supposed to do with this PIN? Well, I’ll show you!
Around line 430 in social_plus.js, you’ll find this bit of code:
var response; response = e.source.evalJS('(p = document.getElementById("oauth_pin")) && p.innerHTML;');
This works just fine in iOS and ancient Android/Chrome builds, but for those Android users who have a phone made in the last 5 years, i.e. every Android user, this is the problem. Here is how I went about fixing it:
function authorizeUICallback(e) { if (!Ti.Android) { var response; response = e.source.evalJS('(p = document.getElementById("oauth_pin")) && p.innerHTML;'); } if ((Ti.Android)&&(called > 0)){ var promptView = Ti.UI.createView({ width:'80%', height:'120dp', layout: "vertical", color:'black', backgroundColor:'gray', bottom:"20%" }), pinField = Ti.UI.createTextField({ width: Ti.UI.FILL, height: Ti.UI.SIZE, hintText: 'Tap Here & Enter PIN', color:'black', }), pinButton = Ti.UI.createButton({ width: Ti.UI.SIZE, height: Ti.UI.SIZE, title: "Authorize" }); Ti.API.error('showTwitterPinPrompt'); webView.setHeight("60%"); webView.setTop(0); promptView.add(pinField); promptView.add(pinButton); view.add(promptView); pinButton.addEventListener('click', function() { if (!pinField.value) { alert('No PIN found'); } else { called = 0; pin = pinField.value; response = 1; response ? ( pin = pinField.value, destroyAuthorizeUI(), receivePinCallback()) : (loadingView && loadingView.hide(), loadingContainer && loadingContainer.hide(), webView && webView.show()), loading = !1, clearInterval(intervalID), estimates[estimateID] = (new Date).getTime() - startTime, Ti.App.Properties.setString("Social-LoadingEstimates", JSON.stringify(estimates)); } }); } called++; if (!Ti.Android) { response ? ( pin = response.split("<code>")[1].split("</code>")[0], destroyAuthorizeUI(), receivePinCallback()) : (loadingView && loadingView.hide(), loadingContainer && loadingContainer.hide(), webView && webView.show()), loading = !1, clearInterval(intervalID), estimates[estimateID] = (new Date).getTime() - startTime, Ti.App.Properties.setString("Social-LoadingEstimates", JSON.stringify(estimates)); } }
For the sake of my sanity, I just target all versions of Android. If you’re NOT dealing with Android, proceed as normal:
function authorizeUICallback(e) { if (!Ti.Android) { var response; response = e.source.evalJS('(p = document.getElementById("oauth_pin")) && p.innerHTML;'); } if (!Ti.Android) { response ? ( pin = response.split("<code>")[1].split("</code>")[0], destroyAuthorizeUI(), receivePinCallback()) : (loadingView && loadingView.hide(), loadingContainer && loadingContainer.hide(), webView && webView.show()), loading = !1, clearInterval(intervalID), estimates[estimateID] = (new Date).getTime() - startTime, Ti.App.Properties.setString("Social-LoadingEstimates", JSON.stringify(estimates)); } }
This is what is called on iOS and here is the Android specific bits:
if ((Ti.Android)&&(called > 0)){ var promptView = Ti.UI.createView({ width:'80%', height:'120dp', layout: "vertical", color:'black', backgroundColor:'gray', bottom:"20%" }), pinField = Ti.UI.createTextField({ width: Ti.UI.FILL, height: Ti.UI.SIZE, hintText: 'Tap Here & Enter PIN', color:'black', }), pinButton = Ti.UI.createButton({ width: Ti.UI.SIZE, height: Ti.UI.SIZE, title: "Authorize" }); Ti.API.error('showTwitterPinPrompt'); webView.setHeight("60%"); webView.setTop(0); promptView.add(pinField); promptView.add(pinButton); //promptView.hide(); view.add(promptView); pinButton.addEventListener('click', function() { if (!pinField.value) { alert('No PIN found'); } else { called = 0; pin = pinField.value; response = 1; response ? ( pin = pinField.value, /*pin = response.split("<code>")[1].split("</code>")[0]*/ destroyAuthorizeUI(), receivePinCallback()) : (loadingView && loadingView.hide(), loadingContainer && loadingContainer.hide(), webView && webView.show()), loading = !1, clearInterval(intervalID), estimates[estimateID] = (new Date).getTime() - startTime, Ti.App.Properties.setString("Social-LoadingEstimates", JSON.stringify(estimates)); } }); } called++;
var called (which was declared at the top of social_plus.js, not shown here) is used to keep track of which screen you’re on during the OAuth authentication. This ensures your users don’t see the pop-up prompt for the PIN when Twitter is asking if you want to allow you application to access the users Twitter details. Now, if you’re using 2-Factor Authentication on your Twitter account, as I am, you’ll see the pop-up a screen too early, but there I haven’t worked out a better solution just yet.
This should give your users a nice pop-up prompt to enter the PIN that’s shown on the Twitter page and then the app can proceed as normal.
I hope this helps you better integrate Twitter into your Appcelerator applications. I’ve tried other solutions for Appcelerator, but social_plus.js was the easiest and most robust solution I’ve found. I plan to add multi-file upload support in the near future and also handle media uploads with the new API (the way social_plus.js handles media is depreciated, but it still works as of this post).
Be sure to check out Aarons work on GitHub and his companies website – Clearly Innovative.