Writing Android Specific Code
In Flutter, writing Android-specific code involves using platform channels to communicate between Dart and native Android (Java/Kotlin) code. This is useful when you need to access Android-specific features that are not available directly through Flutter's SDK.
Step 1: Create a Platform Channel
A platform channel is a communication bridge between Dart and native Android code.
- Set up the channel in Dart code: Use the
MethodChannel
class to communicate with the Android native side.
import 'package:flutter/services.dart';
class AndroidSpecificCode {
static const MethodChannel _channel = MethodChannel('com.example.android_specific_code');
static Future<String> getAndroidVersion() async {
try {
final String version = await _channel.invokeMethod('getAndroidVersion');
return version;
} on PlatformException catch (e) {
return "Failed to get Android version: '${e.message}'.";
}
}
}
- Channel name:
com.example.android_specific_code
(must match between Dart and Android).
Step 2: Implement Native Android Code
- Open the Android project in your Flutter app. Navigate to
android/app/src/main/java/.../MainActivity.java or .kt.
- Modify the MainActivity:Add a method call handler to listen for messages from the Dart side.
package com.example.android_specific_code
import android.os.Build
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.android_specific_code"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getAndroidVersion") {
val androidVersion = "Android ${Build.VERSION.RELEASE}"
result.success(androidVersion)
} else {
result.notImplemented()
}
}
}
}
Step 3: Use the Platform Channel in Flutter
Call the platform-specific method in Dart.
import 'package:flutter/material.dart';
import 'android_specific_code.dart'; // Import the class with platform channel logic
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Android-Specific Code")),
body: Center(
child: FutureBuilder<String>(
future: AndroidSpecificCode.getAndroidVersion(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text("Error: ${snapshot.error}");
} else {
return Text("Android Version: ${snapshot.data}");
}
},
),
),
),
);
}
}
Step 4: Test the App
- Run the app on an Android emulator or device.
- You should see the Android version displayed in the app.
main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
void main() => runApp(DeviceApp());
class DeviceApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Browser Opener',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: HomePage(
pageTitle: 'Flutter Browser Opener',
),
);
}
}
class HomePage extends StatelessWidget {
HomePage({Key? key, required this.pageTitle}) : super(key: key);
final String pageTitle;
static const platform = MethodChannel('com.deviceapp.flutter/browser');
Future<void> _launchBrowser() async {
try {
final int result = await platform.invokeMethod('launchBrowser', Map<String, String>{
'url': 'https://www.google.com',
});
} on PlatformException catch (e) {
print("Error: Unable to open browser. ${e.message}");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(pageTitle),
),
body: Center(
child: ElevatedButton(
child: Text('Open Browser'),
onPressed: _launchBrowser,
),
),
);
}
}
MainActivity.java
package com.deviceapp.flutter;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.deviceapp.flutter/browser";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
String url = call.argument("url");
if (call.method.equals("launchBrowser")) {
openBrowser(call, result, url);
} else {
result.notImplemented();
}
}
}
);
}
private void openBrowser(MethodCall call, MethodChannel.Result result, String url) {
Activity activity = this;
if (activity == null) {
result.error("ACTIVITY_NOT_AVAILABLE", "Browser cannot be opened without a foreground activity", null);
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
result.success(true);
}
}