Consume Flutter on Native Android and iOS via Artifactory Registry

Hamzah Tossaro
4 min readFeb 1, 2024

--

Image by buffaloboy on Shutterstock

Assalamu’alaikum!

Previously I’ve shared how I consumed my existing React Native App on my Super App Native here. Now, I want to share how I consume my another hybrid app wich is Flutter based on my Super App Native using Artifact Registry.

I’ve followed step by step that Flutter documentation said here, but they didn’t said anything for publishing our Flutter to Artifactory Registry.

Using Prebuilt Module Example

Let’s get started with Flutter prebuilt module example project that flutter have here. According to README file, you can get up and running quickly by running below script :

#!/bin/bash
set -e

cd flutter_module/
flutter pub get

# For Android builds:
flutter build aar
open -a "Android Studio" ../android_using_prebuilt_module/ # macOS only
# Or open the ../android_using_prebuilt_module folder in Android Studio for
# other platforms.

# For iOS builds:
flutter build ios-framework --xcframework --output=../ios_using_prebuilt_module/Flutter
open ../ios_using_prebuilt_module/IOSUsingPrebuiltModule.xcodeproj

Android

I’ve tried adding maven-publish on build.gradle at .android folder, but it won’t upload all the dependency required, only the flutter module (app). So, I’ve created publications script that including all subproject for publishing to artifactory registry (ex: gitlab package registry) :

subprojects {
apply plugin: "maven-publish"

def inputFileProject = new File(rootDir, '../pubspec.yaml')
String projectNameLine = inputFileProject.readLines().find { line->
line.startsWith("name:")
}
def projectName = projectNameLine.split(":")[1].trim()
String projectVersionLine = inputFileProject.readLines().find { line->
line.startsWith("version:")
}
def projectVersion = projectVersionLine.split(":")[1].trim().split("\\+")[0].trim()

project.afterEvaluate {
if (!plugins.hasPlugin("android")) {
group = "YOUR.GROUP"
if (project.name == "flutter") version = projectVersion as String

publishing {
publications {
aar(MavenPublication) {
afterEvaluate {
artifactId = project.name
if (project.name == "flutter") artifactId = "$projectName"

if (plugins.hasPlugin("java")) {
from components.java
} else if (plugins.hasPlugin("android-library")) {
def generalRelease = components.find { it.name == "generalRelease" }
if (generalRelease != null) from generalRelease else from components.release
tasks.withType(GenerateModuleMetadata) { enabled = false }
}
}
}
}
repositories {
maven {
url = uri("https://gitlab.com/api/v4/projects/YOUR_REPO_ID/packages/maven")
credentials(HttpHeaderCredentials) {
name = 'Deploy-Token'
value = "YOUR_DEPLOY_TOKEN"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
}
}
}

Save the script inside .android folder (ex: publications.gradle) adjust the value of YOUR.GROUP, YOUR_REPO_ID, YOUR_DEPLOY_TOKEN. Then apply on build.gradle:

...
apply from: file("publications.gradle")

Now, we ready to publish all dependencies together with your Flutter App as Library to artifactory registry, you can run this command at .android folder:

./gradlew publish

After all libraries published, then you can consume your library depend on where your library stored on package registry. example gitlab:

//build.gradle
...
allprojects {
repositories {
...
maven {
url = uri("https://gitlab.com/api/v4/projects/YOUR_REPO_ID/packages/maven")
credentials(HttpHeaderCredentials) {
name = "Deploy-Token"
value = "YOUR_DEPLOY_TOKEN"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
//app/build.gradle
...
dependency {
implementation("YOUR_GROUP:YOUR_APP:VERSION")
...
}

iOS

First, you need to run below script at flutter_module folder:

flutter build ios-framework --cocoapods

You will have one folder created on build directory called ios which have framework folder contains Debug, Profile and Release variant. Each variant have their Flutter.podspec and many .xcframework’s folder.
At Flutter documentation we could use that Flutter.podspec only and the other (.xcframework) must be included to the host app manually.

So, if we want to automate all of the required dependencies framework, we need to publish it somewhere and create one .podspec to mapping frameworks. Here I put all of that .xcframework’s inside at git repository (ex: gitlab).

Second, you must create one .podspec (ex: ModuleName.podspec):

Pod::Spec.new do |s|
s.name = 'ModuleName'
s.version = '0.0.1'
s.summary = 'Example Module.podpsec'
s.description = 'Example Module.podpsec'
s.homepage = 'YOUR_REPO_URL'
s.license = ''
s.author = { 'Hamzah Tossaro' => 'hamzah.tossaro@gmail.com' }
s.source = { :http => 'YOUR_REPO_URL_RAW.zip' }
s.platform = :ios, '12.0'
s.vendored_frameworks = '*.xcframework'
end

Last, push all of .xcframework’s folder also with Flutter.podspec and new .podpsec (ex: ModuleName.podspec) that previously created to git repository.

After all pushed to git repository, then you can consume it on your Podfile:

platform :ios, '12'

target 'IOSUsingPrebuiltModule' do
use_frameworks!
# for development
# pod 'Flutter', :podspec => '../Flutter.podspec'
# pod 'Module', :path => '../'

# for release
pod 'Flutter', :podspec => 'YOUR_REPO_URL_RAW_TO/Flutter.podspec'
pod 'ModuleName', :git => 'YOUR_REPO_URL.git'
end

Conclussion

Same with consuming React Native App before, with this capabilities, we can have a Super App that consuming many Mini App from our currently running project Flutter App without re-write it to native app. And it should work both android and iOS as well.

Alhamdulillah..
I am very grateful to Allah for the knowledge that I’ve got, then hope this knowledge will help you decouple your Flutter with Host app.

That’s all from me, please correct me if something is wrong and feel free to ask questions if you face any problem.
Wassalamu‘alaikum!

*Source Code

--

--