Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build Android APK in Jetbrains Rider

I can't find option to build apk from xamarin project in Rider IDE. Thanks

like image 904
Anandh Avatar asked Oct 16 '22 08:10

Anandh


1 Answers

It is not possible directly (or maybe in 2019.3, I haven't updated yet), but as far as producing release version, with consistent / automatically updated build number, zip aligned and signed apk, You can use an extra tool, like for example cake, that could leverage MSBuild and handle all the process of increasing the build number, cleaning / restoring the nugget packages, building/signing/ZipAlignin the apk, running tests, uploading the apk to your server/google.

Here is a example of such a Cake file:

#addin "Cake.AndroidAppManifest"
#addin nuget:?package=Cake.Git
#tool nuget:?package=NUnit.ConsoleRunner&version=3.9.0


var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
var SolutionFile = "../MyProject.sln"; 
var projectToBuild = "./MyProject.Droid.csproj";
var buildDir = Directory("./bin") + Directory(configuration);
var objDir = Directory("./obj") + Directory(configuration);

var pkg = "com.organisation.app";
var AndroidSDK = "/Users/Me/Library/Developer/Xamarin/android-sdk-macosx";
var AndroidBuildToolsVersion = "28.0.3";
int rc = 0;

// the build number will be set to the commit number. First commit, bn = 1,...

var buildNumber = GitLog(Directory(".."), int.MaxValue).Count; 

Task("Clean")
    .Does(() =>
{
    CleanDirectory(buildDir);
    CleanDirectories(objDir);
});

Task("Restore")
    .IsDependentOn("Clean")
    .Does(() =>
{
    NuGetRestore(SolutionFile);
});

Task("Increase build number")
    .IsDependentOn("Restore")
    .Does(() =>
{
    var pathToAndroidManifest = "./Properties/AndroidManifest.xml";
    var manifest = DeserializeAppManifest(new FilePath(pathToAndroidManifest));
    manifest.VersionCode = buildNumber;
    SerializeAppManifest(new FilePath(pathToAndroidManifest), manifest);
});

Task("Build")
    .IsDependentOn("Increase build number")
    .Does(() =>
{
    MSBuild("../MyProject.sln", new MSBuildSettings().SetConfiguration(configuration));
});

Task("Tests")
    .IsDependentOn("Build")
    .Does(() =>
{
});

Task("package")
    .IsDependentOn("Tests")
    .Does(() =>
{
    // Creates the initial build of an apk.
    MSBuild(projectToBuild, s => {
        s.SetVerbosity(Verbosity.Quiet);
        s.SetPlatformTarget(PlatformTarget.MSIL);
        s.SetConfiguration(configuration);
        s.WithTarget("SignAndroidPackage");
        s.WithProperty("SolutionDir", "../");
    });
});

Task("zipAlign")
    .IsDependentOn("package")
    .Does(() =>
{
    Information("Zip-aligning APK");
    rc = StartProcess($"{AndroidSDK}/build-tools/{AndroidBuildToolsVersion}/zipalign", new ProcessSettings {
        Arguments = new ProcessArgumentBuilder()
            .Append("-f")
            .Append("-v 4")
            .Append($"{buildDir}/{pkg}-Signed.apk")
            .Append($"{buildDir}/{pkg}.apk")
    });
    if (rc == 0) {
        Information("APK Zip Alignment succeeded.");
    } else { 
        var msg = "APK Zip Alignment failure.";
        throw new Exception(msg); 
    }
});

Task("Signing")
    .IsDependentOn("zipAlign")
    .Does(() =>
{
    var keystore = $"../keystore/release.keystore";
    var pass = "*********";

    Information("Signing apk...");
    rc = StartProcess($"{AndroidSDK}/build-tools/{AndroidBuildToolsVersion}/apksigner", new ProcessSettings {
        Arguments = new ProcessArgumentBuilder()
            .Append("sign")
            .Append("--ks")
            .Append(keystore)
            .Append($"--ks-pass pass:{pass}")
            .Append($"{buildDir}/{pkg}.apk")
    });

    if (rc != 0) { 
        var msg = "APK Signing failed.";
        throw new Exception(msg); 
    }
});

Task("Tag")
    .IsDependentOn("Signing")
    .Does(() => {
        Information("Adding a github tag with the build number");
        GitTag(Directory(".."), $"{buildNumber}");
    });

Task("Publish")
    .IsDependentOn("Tag")
    .Does(() =>
{
    Information("Publishing with FastLane");
    var jsonFile = $"../keystore/apiKey.json";
    var apk = $"{buildDir}/{pkg}.apk";

    Information("Publishing to google play with fastlane supply");

    rc = StartProcess("fastlane", new ProcessSettings {
        Arguments = new ProcessArgumentBuilder()
            .Append("supply")
            .Append("--json_key")
            .Append(jsonFile)
            .Append("--package_name")
            .Append(pkg)
            .Append("--apk")
            .Append(apk)
            .Append("--track")
            .Append("beta")
    });
});

Task("Default")
    .IsDependentOn("Publish");

RunTarget(target);
like image 130
Florian Burel Avatar answered Oct 19 '22 00:10

Florian Burel