Cette publication est accessible gratuitement

Partagez cette publication

FAKE, the F# Make with Android and Xamarin
What's FAKE?
Fake is a DSL permitting to write advanced automated builds in FSharp.
It can be used by beginners in FSharp because the DSL can hide some FSharp code comlexity.
We can define multiple targets like in a Makefile.
For example:
letbuildDir ="./build/"Target"Clean"(fun_-> trace"cleaning ..." CleanDir buildDir ) Target"Packages"(fun_-> trace"Restoring nugets" RestorePackages() ) Target"Compile"(fun_-> MSBuildRelease androidBuildDir"Build"!!"src/**/*.csproj" |> Log"AppBuild-Output: "// We use MSBuild and XBuild for .net projects but we can extend the DSL to use everything else) Target"Tests"(fun_->// we can run the unit tests ...) Target"Install"(fun_->// if we use an integration server, we can deploy the project// but we can also install an app like a classic "make install" buildDir  |> directoryInfo  |> filesInDir  |> Seq.map (funf->f.FullName)  |> CopyFiles ProgramFilesX86 ) // define the target ordering and dependencies"Clean" ==>"Packages" ==>"Compile" ==>"Tests" ==>"Install"// if no target is specified in args, we run "Install"RunTargetOrDefault"Install"
Build an APK with FAKE
Build and publish a simple APK
Fake contains the XamarinHelper module helping developers to script their APK building.
There is also the AndroidPublisher module permitting to upload the APK on the Google Play Store.
In the following sample, we can build Apk with the default target and publish them with the ͞Puďlish͟ target.
Usage Fake.exe"build.fsx "target=publish"
#r"packages/FAKE/tools/FakeLib.dll"letandroidBuildDir ="./build/"letandroidProdDir ="./pack/"androidProdDir |> ensureDirectory //Clean old apkTarget"Clean"(fun_-> CleanDir androidBuildDir  CleanDir androidProdDir ) Target"Android-Package"(fun()-> AndroidPackage(fundefaults-> { defaultswith ProjectPath ="Path to my project Droid.csproj" Configuration ="Release" OutputPath = androidBuildDir  Properties = ["MSBuild property","MSBuild property value"]  })  |> AndroidSignAndAlign (fundefaults-> { defaultswith KeystorePath =@"path to my file.keystore" KeystorePassword ="my password" KeystoreAlias ="my key alias" })  |>funfile->file.CopyTo(Path.Combine(androidProdDir, file.Name)) |> ignore ) Target"Publish"(fun_->// I like verbose script trace"publishing Android App"letapk=androidProdDir  |> directoryInfo  |> filesInDir  |>Seq.filter(funf->f.Name.EndsWith(".apk"))  |>Seq.exactlyOne letapkPath = apk.FullName  tracefn"Apk found: %s"apkPath letmail ="my service account mail@developer.gserviceaccount.com"-// Path to the certificate file probably named 'Google Play Android Developer xxxxxxxxxxxx.p12'
letcertificate =newX509Certificate2 ( @"Google Play Android Developer-xxxxxxxxxxxx.p12", "notasecret", X509KeyStorageFlags.Exportable  ) letpackageName ="my Android package name"// to publish an alpha version: PublishApk  { AlphaSettingswith Config =  {  Certificate = certificate;  PackageName = packageName;  AccountId = mail;  Apk = apkPath;  }  } ) Target"Android-Build"(fun_-> !!"**/my project Droid.csproj" |> MSBuildRelease androidBuildDir"Build" |> Log"BuildAndroidLib-Output: ") Target"Default"(fun_-> trace"Building default target" RestorePackages() ) "Clean" ==>"Android-Package" ==>"Default"RunTargetOrDefault"Default"
Build one APK per ABI
I modified XamarinHelper to give the possibility to specify ABI target when using AndroidPackage.
As described inhttp://developer.xamarin.com/guides/android/advanced_topics/build-abi-specific-apks/, multiple APK support is good for reduce the size of the APK and support different CPU architectures.
I͛ŵ Ŷot faŶ of edžĐessivelLJ Đoŵpledž versioŶ Đode geŶeratioŶ.I published some applications using a simpliest method. I just increment of 1 each ABI version code.
Google imposes only one constraint:
We must respect the order x86 < x86_64 < ArmEabi < ArmEabiV7a < Arm64V8a.
For example, if your debug version code is 5, your APKS͚s versioŶ Đodesshould be:
5 for MyApp-X86.apk 6 for MyApp-X86_64.apk 7 for MyApp-armeabi.apk 8 for MyApp- armeabi-v7.apk 9 for MyApp- armeabiv64-v8a.apk
The next built script example is use forhttps://bitbucket.org/rflechner/sokoban/overview
//#r "packages/FAKE/tools/FakeLib.dll"#I "/Users/rflechner/Documents/development/FAKE/build"#r "FakeLib.dll"openSystem openSystem.IO openFake openXamarinHelper openAndroidPublisher letandroidBuildDir ="./build/"letandroidProdDir ="./pack/"androidProdDir |> ensureDirectory Target"Clean"(fun_> CleanDir androidBuildDir  CleanDir androidProdDir ) Target"AndroidPackage"(fun()> AndroidPackage(fundefaults> { defaultswith ProjectPath ="Sokoban.Droid/Sokoban.Droid.fsproj" Configuration ="Release" OutputPath = androidBuildDir  })  |>funfile>file.CopyTo(Path.Combine(androidProdDir, file.Name)) |> ignore ) Target"AndroidMultiPackages"(fun()>letversionStepper = (funv t>matchtwith |AndroidAbiTarget.X86c>v + 1  |AndroidAbiTarget.X86And64c>v + 2  |AndroidAbiTarget.ArmEabic>v + 3  |AndroidAbiTarget.ArmEabiV7ac>v + 4  |AndroidAbiTarget.Arm64V8ac>v + 5  | _>v) letabis =AndroidPackageAbiParam.SpecificAbis ([AndroidAbiTarget.X86({ SuffixAndExtension="x86.apk"; }) AndroidAbiTarget.ArmEabi({ SuffixAndExtension="armeabi.apk"; }) AndroidAbiTarget.ArmEabiV7a({ SuffixAndExtension="armeabiv7a.apk"; }) AndroidAbiTarget.X86And64({ SuffixAndExtension="x86_64.apk"; })  ]) letfiles = AndroidBuildPackages(fundefaults> { defaultswith ProjectPath ="Sokoban.Droid/Sokoban.Droid.fsproj"
 Configuration ="Release" OutputPath = androidBuildDir  PackageAbiTargets = abis  VersionStepper =Some(versionStepper)  }) forfinfilesdo printfn" apk: %s"f.Name  files  |>Seq.iter (funfile>file.CopyTo(Path.Combine(androidProdDir, file.Name)) |> ignore) ) Target"AndroidBuild"(fun_> !!"**/Sokoban.Droid.fsproj" |> MSBuildRelease androidBuildDir"Build" |> Log"BuildAndroidLibOutput: ") Target"Default"(fun_> trace"Building default target" RestorePackages() ) "Clean" ==>"AndroidPackage" ==>"Default"RunTargetOrDefault"Default"
Fake.exe build.fsx "target=Android-Package"
Fake.exe build.fsx "target=Android-MultiPackages"
Un pour Un
Permettre à tous d'accéder à la lecture
Pour chaque accès à la bibliothèque, YouScribe donne un accès à une personne dans le besoin