Build multiple apps with different assets but using the same code - android

I am currently changing my apps, made with Swift and Java, to Flutter, however, right now I have 5 Apps for android and iOS, all using the same code (5 in Swift, 5 in Java), and, for each one I have different assets, like images, strings, API url's etc. In case of an iOS app I was currently creating different Targets on XCode, with different user-defined variables that i use in the code, and then I chose which target I want to build and send to the corespondent iTunesConnect app. In android I do more or less the same, but using Android flavors.
My doubt is how can I do this in flutter without being forced to create a different Flutter project for each app I want to build.
Any ideas on what approach should I use?

I use a custom build script that creates a symlink depending on the flavor name
From my Grinder build script
Future<void> _setTenant(Tenant tenant) async {
const symlinkPath = 'assets/tenant';
final link = Link(symlinkPath);
if (link.existsSync() &&
link.targetSync() == '../assets/${tenant.identifier}') {
return;
}
if (link.existsSync()) {
link.updateSync('../assets/${tenant.identifier}');
} else {
Link(symlinkPath).createSync('../assets/${tenant.identifier}');
}
}
Tenant is a custom class and Tenant.identifier returns a string that is valid as directory/symlink name.
I created https://github.com/flutter/flutter/issues/21682 to get direct support for that in Flutter.

Related

Android Asset Delivery in Dotnet Maui

I have a .NET MAUI Project with a lot of assets (images) in the Resources\Images directory that shall be deployed to the Google Play Store. This means that the size of the generated aab package is way beyond the Google Play Store limit of 150MB.
(Message: Your App Bundle contains the following configurations where the initial install would exceed the maximum size of 150 MB...)
My current solution resizes the images to <= 150MB. I now saw that there is the possibility to generate separate files for the assets, which is called Play Feature Delivery.
From this sample project I get the following gradle file to create an install-time-package:
apply plugin: 'com.android.asset-pack'
assetPack {
packName = "install_time_asset_pack" // Directory name for the asset pack
dynamicDelivery {
deliveryType = "install-time" // delivery mode
}
}
My question is: Can this somehow be done with .NET MAUI? Is it possible to add some elements to the csproj-file to do this, just like for example for the keystore:
<PropertyGroup Condition="$(TargetFramework.Contains('-android')) and '$(Configuration)' == 'Release'">
<AndroidKeyStore>True</AndroidKeyStore>
<AndroidSigningKeyStore>..\myapp.keystore</AndroidSigningKeyStore>
<AndroidSigningKeyAlias>key</AndroidSigningKeyAlias>
<AndroidSigningKeyPass>SuperSecretPassword!</AndroidSigningKeyPass>
<AndroidSigningStorePass></AndroidSigningStorePass>
</PropertyGroup>
The characteristic of the app and the users makes it impossible to load the images at runtime, e.g. via https.
tl;dr I did not find any Maui answer at this time.
The best starting point looks like XamarinComponent/Android/GoogleAndroidVending.
HOWEVER that wraps a java library, and appears to use gradle, so TBD what knowledge is required to be able to build this, then adapt it for Maui.
The corresponding Xamarin.Forms doc is APK Expansion Files.
The Xamarin.Forms nuget source code and doc is at github XamarinComponents/Android/GoogleAndroidVending.
There is a Nuget link there, but that won't work in .Net Maui.
Until there is a Maui Nuget, it will be necessary to download the source code, and modify it. (If anyone does this, would be good to upload back to github. TBD where.)
App Startup is a bit different in .Net Maui, I did not investigate what might need to change.
In addition, there might be references to Xamarin namespaces that should change to Maui equivalents.
IMPORTANT: This c# code is a wrapper for a java library from Google. The project includes gradle references. TBD what the requirements are to build this.
If your APK is getting over 150Mb then I suspect Google and Apple (if you're making an iOS app) will be expecting you to host the image data in the cloud and pull it to the device on an 'as needed' basis so you're not clogging your users' device storage up unnecessarily. That type of static imagery should be stored in cache and not backed up (so you'll need to check if it exists and re-download if necessary).

Android NDK apps - best way to integrate a text file for deployment

I'm testing the creation of the Android apps integrating C++ code. In this example I'm using the OpenCV library
I setup the environment and I was also able to compile and deploy. The app works correctly. Beautiful until here. There is a little UX problem though. The app makes use of two xml files:
haarcascade_frontalface_alt.xml
haarcascade_eye_tree_eyeglasses.xml
but at the moment the final user needs to post-download them on device and in a given folder, otherwise the app would be unable to perform the respective detections. The significant part of code so far is the following:
JNIEXPORT void JNICALL Java_com_demo_test_opencvsample_OpenCVClass_faceDetection
(JNIEnv *, jclass, jlong addrRgba){
Mat& frame = *(Mat*)addrRgba;
detect(frame);
}
void detect(Mat& frame){
// these files will be loaded from a specific folder in the phone memory
String face_cascade_name = "/storage/emulated/0/data/haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "/storage/emulated/0/data/haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
//-- 1. Load the cascades
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return; };
if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n"); return; };
-> question: is there a way to integrate the two xml files directly in the apk avoiding a final user to have to download them separately on his device after the installation of the app? I would like him to have them directly available after the app gets installed and the C++ code, also because they are not supposed to be changed
NOTE before answering: I'm not interested in putting two download buttons in the final app and not even in having a full-android solution. I would like to maintain the current architecture making use of the C++ core
Thanks in advance to those who will try to help
The Asset API is mentioned as available in android NDK levels which forwards to this page android ndk asset_manager.h
In here it describes a set of APIs which are fopen like, which allow bundled assets to be opened.
Hard-coding paths is not the correct way to manage your files, as different devices, or future/past operating systems may rearrange the file system.
SO : How to get ExternalDirectory in NDK shows how in general to call android functions from NDK, and specifically how to load the externalDirectory - the root directory of the sdcard (user visible when a device is attached to a computer.
For files which are only related to your project (which seems to be the case here), I would recommend storing the xml files in the application directory, which can be accessed through jni from Context->getFilesDir() (see android : Context
If your xml files are static, and unlikely to change more frequently than your application, use assets.
If your xml files will be updated by the application, or yourself, use the getFilesDir()
If you want your uses to see the XML files, (and be able to edit them?) then use getExternalDirectory()

Build different APKs for different environments (Xamarin.Android)

We're building a Xamarin.Android application that connects to the cloud.
We have different Cloud URLs for different environments, namely Development, Staging and Production.
I find myself manually changing URLs everytime I generate an APK for a particular environment.
I came across Gradle/ANT ways of changing "flavours" but since it is not available in Xamarin, How do I go about it? How does one manage different environments in Xamarin? Is it using MSBuild config files? Any help would be appreciated!
EDIT:
What I currently have:
/// <summary>
/// The application URL for PROD
/// </summary>
//private const string ApplicationUrl = "https://prod.azure-mobile.net/";
/// <summary>
/// The application URL for DEV
/// </summary>
private const string ApplicationUrl = "https://dev.azure-mobile.net/";
In this case, we manually comment/uncomment URLs for different builds (Dev/Staging/Prod) and generate APKs. I understand it's not an optimal solution and is prone to mistakes.
I would probably define different build configurations (in the Project Options) for Development, Staging and Production. You could then define symbols (in the Compiler page of the options) and use preprocessor directives to change the definition of ApplicationUrl in the code. Building each one is then just a matter of selecting the appropriate configuration in the drop-down.
I'd also change the output path for each configuration so the APKs get written to different folders to reduce any possible confusion about which configuration each APK is built with.
Disadvantage is that if you change any other project options you need to ensure you make the change for every configuration, but as this isn't done very often it's probably a reasonable compromise.

Is it possible to pixelate an image in appcelerator Titanium?

I'm writing an Android and IOS app using Appcelerator Titanium, and I can't find a way to pixelate an image. The app that I'm writing, needs to do that: pixelate a given image with a parameter given by user, (the greater the number, the greater the pixels). I have found a way to do it with Xcode for IOS, and in Android SDK for Android, but if possible, I would like to do it in Titanium to avoid writing the whole app twice, one for Android and other for IOS.
Is there a way to do it?
Thank you.
If you have a native way in iOS and both Android you should wrap these as native modules and then include them in the project.
Follow this guide here on the Community wiki ->
https://wiki.appcelerator.org/display/guides2/Creating+a+New+Titanium+Module
Then you can write a function that wraps the modules and returned the processed object. eg.
var processImage = function() {
if (Titanium.Platform.name == 'android') {
// Android stuff
var imageProcess = require('ti.imageProcess');
return imageProcess.doImage('/voo/bar', /*more options */)
} else {
// etc
}
};
Instead of writing and maintaining two modules you could use a webView and use a JS library or the canvas object to pixelate the image.
A JS canvas solution to this can be found here:
https://stackoverflow.com/a/19129822/2132015

Brandable Android Application

We service multiple clients. One feature we want to offer is an android application which allows the client to custom brand the application (icons, logos, names, etc).
Here are a few stipulations.
Customers of clients will use this app.
You could be a customer of more than one client, but we cannot show the user any kind of list of clients.
Clients cannot share a single app.
The app must be able to look different per client, even though the functionality is the same
Yes, I know it's a PITA to build it this way, but our clients don't want customers of other clients to know they are also our client.
So, what is the best way to build an easily brandable application with as little strain on the developer's sanity as possible?
Keep a separate res/ folder for each version of the app. Give every icon, logo and String the same name but tailor the content for each client, and build a different .apk for each by simply dropping that res folder into the build. I don't think you can make custom qualifiers work for this and just make a single .apk - and this would in any case bundle every client's custom pictures and Strings in to everyone's application.
I would start by developing a script for a global re-name, since you'll need that anyway (can be done fairly simply with find, xargs and sed)
You'll need tools for making the customizations to resources, that could be the SDK & Eclipse plug-in
Perhaps you could create some kind of wizard extending the Eclipse plug-in.
Or with a lot of work but easier usage, you could do something stand alone that drives the necessary command line tools to build the generated package.
You can do what #Jems said or (presuming that the app comunicates with a server) put the "logic" on the server side.
The first time you run the application the server will send you the resources corresponding to your client that you store locally.
Problems with this approach: The first time you may have to download a load of stuff...
Advantages: You just have to change a properties string saying which is the server, or the login to the server to know what it has to send changing the layout without having to deploy another app with different resources.
It really depends if you want to support layout changes on server side.
Build time solution using gradle could be achieved with productFlavors feature, described in http://blog.robustastudio.com/mobile-development/android/building-multiple-editions-of-android-app-gradle/
Flavors (aka customer brands) could be defined in build.gradle file in the following way (different package names are here to deploy each branded apk as separate application):
productFlavors {
vanilla {
applicationId "com.example.multiflavorapp"
}
strawberry {
applicationId "com.example.multiflavorapp.strawberry"
}
}
Specific android resources for brand could be then placed (instead of src/main/res directory) into src/vanilla/res or src/strawberry/res directories (in this case vanilla and strawberry are the brands). Please be aware that using productFlavors feature, gradle does no merging of assets, only simple replacing files without any knowledge about specific res subdirectories.
During building proces gradle creates build variants as combination of build type (debug,release) and productFlavor, more at http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Type-Product-Flavor-Build-Variant.

Categories

Resources