Calling Native Android Code from Flutter (Step-by-Step for Beginners)
When you need to run platform-specific features (like background services, Bluetooth, or sensors) that Flutter doesn’t handle out of the box, you can use MethodChannels to talk to native Android or iOS code.
In this tutorial, we’ll:
-
Create a MethodChannel in Flutter.
-
Set up a foreground service in Android.
-
Trigger that service from Flutter—even when the app is closed.
1. What Is a MethodChannel?
Think of a MethodChannel as a telephone line between Flutter (Dart) and the platform’s native code (Java/Kotlin for Android, Swift/Objective-C for iOS).
-
Flutter side: “📞 Hey Android, please start the service!”
-
Android side: “✅ Got it, I’m starting it now.”
2. Create the Channel in Flutter
Create a new file: lib/native_service.dart
Key points:
-
MethodChannel('com.example/native_service')
: Use a simple, descriptive name.
-
invokeMethod('startService')
: Sends a message to Android.
3. Call It from Your First Screen
In your main screen’s initState
, trigger the service as soon as the app starts:
4. Listen for Calls on Android
Open android/app/src/main/kotlin/.../MainActivity.kt
and configure the MethodChannel:
5. Build the Foreground Service
Create MyService.kt
in the same package:
import android.app.*
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import org.json.JSONObject
class MyService : Service() {
private var url = ""
private var token = ""
private val CHANNEL_ID = "MyServiceChannel"
private val NOTIFICATION_ID = 1
override fun onBind(intent: Intent?): IBinder? = null
override fun onCreate() {
super.onCreate()
createNotificationChannel()
startForeground(NOTIFICATION_ID, createNotification())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
url = intent?.getStringExtra("url") ?: ""
token = intent?.getStringExtra("token") ?: ""
return START_STICKY
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
if (url.isEmpty() || token.isEmpty()) {
Log.e("MyService", "❌ Missing URL or Token")
stopSelf()
return
}
// 🔗 Send a POST request when app is removed
val queue = Volley.newRequestQueue(this)
val jsonBody = JSONObject().apply { put("isOnline", false) }
val request = object : StringRequest(
Method.POST, url,
{ response ->
Log.d("MyService", "✅ Response: $response")
stopForeground(true); stopSelf()
},
{ error ->
Log.e("MyService", "❌ Error: ${error.message}", error)
stopForeground(true); stopSelf()
}
) {
override fun getBody() = jsonBody.toString().toByteArray(Charsets.UTF_8)
override fun getBodyContentType() = "application/json; charset=utf-8"
override fun getHeaders() = hashMapOf(
"Content-Type" to "application/json",
"Authorization" to "Bearer $token"
)
}
queue.add(request)
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID, "My Service", NotificationManager.IMPORTANCE_LOW
)
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
}
}
private fun createNotification(): Notification =
NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Status Service")
.setContentText("Running in background…")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.build()
}
6. Update Android Manifest
Inside <application>
in AndroidManifest.xml
:
How It All Works
-
Flutter sends a message through the MethodChannel.
-
Android (MainActivity) receives it and starts MyService.
-
MyService becomes a foreground service, ensuring it runs even when your app is closed or swiped away.
-
The service performs a task (like sending a network request) and then stops itself.
Takeaways for Beginners
-
MethodChannel is the bridge between Flutter and native code.
-
Always use startForegroundService
for tasks that need to survive app termination.
-
Keep the channel name generic (com.example/native_service
) so it can be reused.
-
Foreground services must show a notification—this is an Android requirement.
Comments
Post a Comment