Monday 13 April 2015

Send email from iOS and Android via Xamarin Forms

Email service with default email composer
Send email from Xamarin Forms requires different implementation for iOS and Android. The default behaviour of using the default email service from each platform will populate a composer, which is visiable to the end user with the option to see, send, cancel, etc.

Concepts:  iOS

Compoment: MFMailComposeViewController
Present MFMailComposeViewController
In order to use the above iOS component as a dependency service, it is required to have a statement to present the view controller explicitly in your code. In this case, we use:
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(mailer, truenull)


Dismiss MFMailComposeViewController
When finished sending the email, it is required to dismiss the view controller manually. The DismissViewController has to be inside the MainThread of iOS.
mailer.Finished += (s,e)=>{
    UIApplication.ShareApplication.InvokeMainThread(()=>{
        ((MFMailComposeViewController)s).DismissViewController(true,()=>{});
    });
}


Set Mime Type for an attachment
It is important to provide the right "Mime Type" to the attachment you plan to add to your email.

Concepts: Android

Intent:  Intent.ActionSend  (Not "Intent.ActionSendTo" ,  using this will cause some error when sending email to exchange or google)
Intent type: "message/rfc822"  (follow the receipe from Xamarin website: http://developer.xamarin.com/recipes/android/networking/email/send_an_email/)

Present Composer
Setting the Intent’s mime type to message/rfc822 causes the mail application to launch. If multiple applications are capable of handling mail, the user will get a list to choose from.
Note: user can choose, sending out a message via gmail, exchange, skype, hangout. whatsapp, etc.

File object:
With the given file path of the attachment, you still need the Java object to form the file object. But, use Android.Net.Uri.FromFile to form the uri to the file.
var file = new Java.IO.File(attachmentPath);
Use intent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(file)


Start Android Activity:

It is important to start the Android activity via the right context.
In Xamarin Forms, we use: 
Forms.Context.StartActivity(intent)
//Not: this.Context.StartActivity(intent)



It is important to set "setReadable()" after obtaining a file object in Android.

Without this line, you would't get the attachment even though you can see the attachment appear in the email composer.
file.SetReadable(true, false)

Usage:
//Example in Xamarin.Forms 
var mailService = DependencyService.Get<IEmailService>(); 
if (mailService.CanSend){
    mailService.ShowDraft("Subject","Body",false"receipient email address""path to the attachment");
}else{
    //Please activate or setup your email account from your device settings.
}

Alternative approach:

MAILTO 
string strMailTo = @"mailto:jeff.wei-lim@artesiansolutions.com?Subject=test&Body=testBody";
Device.OpenUri(new Uri(strMailTo));

Note for using MailTo:
  1. user can choose, sending out a message via email client only (such as email app or gmail...)
  2. Unable to send an email with attachment.

Tuesday 7 April 2015

TeamCity with Xamarin Form

This is my second time setting up the end-to-end continuously integration(CI) /build for mobile application development. The 1st project was purely an end-to-end process for iOS project, with TestFlightApp. This time, I have extended my previous experience to both iOS  and Android projects. 

This page contain information about entities that involved using SVN, TeamCity to compile mobile applications written in Xamarin Forms, and build the projects from the build agent, and finally submit them to TestFairy (No more TestFlight).
It is a complete end-to-end continuously process with the facilities to dispatch to app to the end user or tester automatically. See the diagram below: 

So, what it does? 

  • Developers - commit changes to SVN via the SVN Client installed in Xamarin Studio.
  • Trigger - used to add builds to the queue when an event occurs (like commit a file)
  • Transfer - transfer file from SVN to Build Agent (setup mac mini as a build agent to TeamCity).
  • Major Build Steps:
    • 'mdtool' on Xamarin PCL shared project
    • 'mdtool' on iOS app
    • 'xbuild' on Android app
  • Custom script for publishing
    • Publish iOS app to TestFairy
    • Publish Android app to TestFairy
  • Test fairy send out invitation email



Example Command:
Command Line to build iOS project:
/Applications/Xamarin\ Studio.app/Contents/MacOS/mdtool -v build --project:YouiOSProject.iOS --configuration:"Ad-Hoc|iPhone" YourSolution.sln;


Command Line to build Android project:
Signed
xbuild /t:SignAndroidPackage /p:Configuration=release Droid/YourDroidProject.csproj

xbuild /t:SignAndroidPackage /p:Configuration=release %teamcity.build.checkoutDir%/Droid/YouDroidProject.csproj

Unsigned:
xbuild /t:PackageForAndroid /p:Configuration=release Droid/YourDroidProject.csproj


Publish YouriOSProject.iOS to TestFairy:
If you need dSYM, then you need to zip it:

zip -r %teamcity.build.checkoutDir%/Pro/build/iOS/iPhone/Ad-Hoc/YouriOSProject.app.dSYM.zip %teamcity.build.checkoutDir%/Pro/build/iOS/iPhone/Ad-Hoc/YouriOSProject.app.dSYM

curl -s http://app.testfairy.com/api/upload -F api_key='xxxxxxxxxxxxxxxxxxxx' -F file=@%teamcity.build.checkoutDir%/Pro/build/iOS/iPhone/Ad-Hoc/YouriOSProject.ipa -F symbols_file=@%teamcity.build.checkoutDir%/Pro/build/iOS/iPhone/Ad-Hoc/YouriOSProject.app.dSYM.zip -F testers_groups='TesterGroupInTestFairy' -F comment=‘Hello Built from TeamCity. %env.TEAMCITY_BUILDCONF_NAME% build#: %changesComment%’

Publish YourAndroidProject.Android to TestFairy
curl -s http://app.testfairy.com/api/upload -F api_key='xxxxxxxxxxxxxxxxxxxxx' -F file=@%teamcity.build.checkoutDir%/Pro/build/Droid/Release/YourDroidProject.pro-Signed.apk -F testers_groups='TesterGroupInTestFairy' -F comment=‘Your Droid Project;Built from TeamCity. %env.TEAMCITY_BUILDCONF_NAME% build#: %changesComment%’


SigningSigning is the most tricky thing for mobile application. For instance, you need to create a specific provisioning profile for iOS project; specific target for Android, etc. Well, I will focusing on some concerns of signing Android application here.

AndroidIn order to run on an Android device, packages must be signed. In order to allow quicker build iteration, the Xamarin.Android tasks do not sign packages during the build process, because signing is quite slow. Instead, they are signed (if necessary) before installation or during export, by the IDE or the Install build target. Invoking the SignAndroidPackage target will produce a package with the "- Signed.apk" suffix in the output directory. 

How to run unit test for your Xamarin Application in AppCenter?

How to run unit test for your Xamarin application in AppCenter?  When we talk about Building and Distributing your Xamarin app, you m...