- Install
- Set up an editor
- Test drive
- Write your first Flutter app, part 1
- Learn more
- Flutter for Android developers
- Flutter for iOS developers
- Flutter for React Native developers
- Flutter for web developers
- Flutter for Xamarin.Forms developers
- Introduction to declarative UI
- Cookbook
- Codelabs
- Tutorials
- User interface
- Introduction to widgets
- Layouts in Flutter
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Introduction to animations
- Animations overview
- Animations tutorial
- Hero Animations
- Staggered Animations
- Advanced UI
- Slivers
- Taps, drags, and other gestures
- Widget catalog
- Data & backend
- State management
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Firebase
- Accessibility & internationalization
- Accessibility
- Internationalizing Flutter apps
- Platform integration
- Writing custom platform-specific code
- Packages & plugins
- Using packages
- Developing packages & plugins
- Background processes
- Tools & techniques
- Android Studio / IntelliJ
- Visual Studio Code
- Upgrading Flutter
- Hot reload
- Code formatting
- Debugging Flutter apps
- Using OEM debuggers
- Flutter's build modes
- Testing Flutter apps
- Performance best practices
- Flutter performance profiling
- Creating flavors for Flutter
- Preparing an Android App for Release
- Preparing an iOS App for Release
- Continuous Delivery using fastlane with Flutter
- Bootstrap into Dart
- Inside Flutter
- Platform specific behaviors and adaptations
- Technical Overview
- Technical videos
- FAQ
- Flutter widget index
- Install
- Windows install
- MacOS install
- Linux install
- Set up an editor
- Write your first Flutter app, part 1
- Learn more
- Cupertino (iOS-style) widgets
- Layout widgets
- Animation and motion widgets
- Retrieve the value of a text field
- Basic widgets
- Material Components widgets
- Animate the properties of a Container
- Fade a Widget in and out
- Add a Drawer to a screen
- Displaying SnackBars
- Exporting fonts from a package
- Updating the UI based on orientation
- Using Themes to share colors and font styles
- Using custom fonts
- Working with Tabs
- Building a form with validation
- Create and style a text field
- Focus on a Text Field
- Handling changes to a text field
- Retrieve the value of a text field
- Adding Material Touch Ripples
- Handling Taps
- Implement Swipe to Dismiss
- Display images from the internet
- Fade in images with a placeholder
- Working with cached images
- Basic List
- Create a horizontal list
- Creating a Grid List
- Creating lists with different types of items
- Place a floating app bar above a list
- Working with long lists
- Report errors to a service
- Animating a Widget across screens
- Navigate to a new screen and back
- Navigate with named routes
- Pass arguments to a named route
- Return data from a screen
- Send data to a new screen
- Fetch data from the internet
- Making authenticated requests
- Parsing JSON in the background
- Working with WebSockets
- Persist data with SQLite
- Reading and Writing Files
- Storing key-value data on disk
- Play and pause a video
- Take a picture using the Camera
- An introduction to integration testing
- Performance profiling
- Scrolling
- An introduction to unit testing
- Mock dependencies using Mockito
- An introduction to widget testing
- Finding widgets
- Tapping, dragging and entering text
- Development
- Introduction to widgets
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Navigate to a new screen and back
- Send data to a new screen
- Return data from a screen
- Navigate with named routes
- Animating a Widget across screens
- AnimatedList
- Sample App Catalog
- Animations overview
- Animations tutorial
- Staggered Animations
- Slivers
- Taps, drags, and other gestures
- Accessibility widgets
- Assets, images, and icon widgets
- Async widgets
- Input widgets
- Interaction model widgets
- Painting and effect widgets
- Scrolling widgets
- Styling widgets
- Text widgets
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Accessibility
- Internationalizing Flutter apps
- Writing custom platform-specific code
- Using packages
- Fetch data from the internet
- Developing packages & plugins
- Background processes
- Android Studio / IntelliJ
- Set up an editor
- Flutter inspector
- Creating Useful Bug Reports
- Visual Studio Code
- Set up an editor
- Upgrading Flutter
- Hot reload
- Code formatting
Writing custom platform-specific code
By default our template supports writing Android code using Java, or iOS code using Objective-C. To use Kotlin or Swift, use the -i
and/or -a
flags:
- In a terminal run:
flutter create -i swift -a kotlin batterylevel
Step 2: Create the Flutter platform client
The app’s State
class holds the current app state. We need to extend that to hold the current battery state.
First, we construct the channel. We use a MethodChannel
with a single platform method that returns the battery level.
The client and host sides of a channel are connected through a channel name passed in the channel constructor. All channel names used in a single app must be unique; we recommend prefixing the channel name with a unique ‘domain prefix’, e.g. samples.flutter.io/battery
.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class _MyHomePageState extends State<MyHomePage> {
static const platform = const MethodChannel('samples.flutter.io/battery');
// Get battery level.
}
Next, invoke a method on the method channel, specifying the concrete method to call via the String identifier getBatteryLevel
. The call may fail—for example if the platform does not support the platform API (such as when running in a simulator), so wrap the invokeMethod
call in a try-catch statement.
Use the returned result to update the user interface state in _batteryLevel
inside setState
.
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
Finally, replace the build
method from the template to contain a small user interface that displays the battery state in a string, and a button for refreshing the value.
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RaisedButton(
child: Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel),
],
),
),
);
}
Step 3a: Add an Android platform-specific implementation using Java
Note: The following steps use Java. If you prefer Kotlin, skip to step 3b.
Start by opening the Android host portion of your Flutter app in Android Studio:
Start Android Studio
Select the menu item ‘File > Open…’
Navigate to the directory holding your Flutter app, and select the
android
folder inside it. Click OK.Open the file
MainActivity.java
located in thejava
folder in the Project view.
Next, create a MethodChannel
and set a MethodCallHandler
inside the onCreate
method. Make sure to use the same channel name as was used on the Flutter client side.
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.io/battery";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
});
}
}
Next, we add the actual Android Java code that uses the Android battery APIs to retrieve the battery level. This code is exactly the same as you would have written in a native Android app.
First, add the needed imports at the top of the file:
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
Then add the following as a new method in the activity class, below the onCreate
method:
private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
Finally, complete the onMethodCall
method added earlier. You need to handle a single platform method, getBatteryLevel
, so test for that in the call
argument. The implementation of this platform method simply calls the Android code written in the previous step, and passes back a response for both the success and error cases using the response
argument. If an unknown method is called, report that instead. Replace:
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
with:
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
You should now be able to run the app on Android. If you are using the Android Emulator, you can set the battery level in the Extended Controls panel accessible from the ...
button in the toolbar.
Step 3b: Add an Android platform-specific implementation using Kotlin
Note: The following steps are similar to step 3a, only using Kotlin rather than Java.
This step assumes that you created your project in step 1. using the -a kotlin
option.
Start by opening the Android host portion of your Flutter app in Android Studio:
Start Android Studio
Select the menu item ‘File > Open…’
Navigate to the directory holding your Flutter app, and select the
android
folder inside it. Click OK.Open the file
MainActivity.kt
located in thekotlin
folder in the Project view. (Note: If you are editing using Android Studio 2.3, note that the ‘kotlin’ folder is shown as-if named ‘java’.)
Next, inside the onCreate
method, create a MethodChannel
and call setMethodCallHandler
. Make sure to use the same channel name as was used on the Flutter client side.
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodChannel
class MainActivity() : FlutterActivity() {
private val CHANNEL = "samples.flutter.io/battery"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
// TODO
}
}
}
Next, add the actual Android Kotlin code that uses the Android battery APIs to retrieve the battery level. This code is exactly the same as you would have written in a native Android app.
First, add the needed imports at the top of the file:
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
Next, add the following as a new method in the MainActivity
class, below the onCreate
method:
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
Finally, complete the onMethodCall
method added earlier. You need to handle a single platform method, getBatteryLevel
, so test for that in the call
argument. The implementation of this platform method simply calls the Android code written in the previous step, and passes back a response for both the success and error cases using the response
argument. If an unknown method is called, report that instead. Replace:
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
// TODO
}
with:
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
You should now be able to run the app on Android. If you are using the Android Emulator, you can set the battery level in the Extended Controls panel accessible from the ...
button in the toolbar.
Step 4a: Add an iOS platform-specific implementation using Objective-C
Note: The following steps use Objective-C. If you prefer Swift, skip to step 4b.
Start by opening the iOS host portion of your Flutter app in Xcode:
Start Xcode
Select the menu item ‘File > Open…’
Navigate to the directory holding your Flutter app, and select the
ios
folder inside it. Click OK.Make sure the Xcode projects builds without errors.
Open the file
AppDelegate.m
located under Runner > Runner in the Project navigator.
Next, create a FlutterMethodChannel
and add a handler inside the application didFinishLaunchingWithOptions:
method. Make sure to use the same channel name as was used on the Flutter client side.
#import <Flutter/Flutter.h>
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
FlutterMethodChannel* batteryChannel = [FlutterMethodChannel
methodChannelWithName:@"samples.flutter.io/battery"
binaryMessenger:controller];
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
// TODO
}];
[GeneratedPluginRegistrant registerWithRegistry:self];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
Next, add the actual iOS ObjectiveC code that uses the iOS battery APIs to retrieve the battery level. This code is exactly the same as you would have written in a native iOS app.
Add the following as a new method in the AppDelegate
class, just before @end
:
- (int)getBatteryLevel {
UIDevice* device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryState == UIDeviceBatteryStateUnknown) {
return -1;
} else {
return (int)(device.batteryLevel * 100);
}
}
Finally, complete the setMethodCallHandler
method added earlier. You need to handle a single platform method, getBatteryLevel
, so test for that in the call
argument. The implementation of this platform method simply calls the iOS code written in the previous step, and passes back a response for both the success and error cases using the result
argument. If an unknown method is called, report that instead.
__weak typeof(self) weakSelf = self
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([@"getBatteryLevel" isEqualToString:call.method]) {
int batteryLevel = [weakSelf getBatteryLevel];
if (batteryLevel == -1) {
result([FlutterError errorWithCode:@"UNAVAILABLE"
message:@"Battery info unavailable"
details:nil]);
} else {
result(@(batteryLevel));
}
} else {
result(FlutterMethodNotImplemented);
}
}];
You should now be able to run the app on iOS. If you are using the iOS Simulator, note that it does not support battery APIs, and the app will thus display ‘battery info unavailable’.
Step 4b: Add an iOS platform-specific implementation using Swift
Note: The following steps are similar to step 4a, only using Swift rather than Objective-C.
This step assumes that you created your project in step 1. using the -i swift
option.
Start by opening the iOS host portion of your Flutter app in Xcode:
Start Xcode
Select the menu item ‘File > Open…’
Navigate to the directory holding your Flutter app, and select the
ios
folder inside it. Click OK.
Next, add support for Swift in the standard template setup that uses Objective-C:
Expand Runner > Runner in the Project navigator.
Open the file
AppDelegate.swift
located under Runner > Runner in the Project navigator.
Next, override the application:didFinishLaunchingWithOptions:
function and create a FlutterMethodChannel
tied to the channel name samples.flutter.io/battery
:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "samples.flutter.io/battery",
binaryMessenger: controller)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: FlutterResult) -> Void in
// Handle battery messages.
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Next, add the actual iOS Swift code that uses the iOS battery APIs to retrieve the battery level. This code is exactly the same as you would have written in a native iOS app.
Add the following as a new method at the bottom of AppDelegate.swift
:
private func receiveBatteryLevel(result: FlutterResult) {
let device = UIDevice.current
device.isBatteryMonitoringEnabled = true
if device.batteryState == UIDeviceBatteryState.unknown {
result(FlutterError(code: "UNAVAILABLE",
message: "Battery info unavailable",
details: nil))
} else {
result(Int(device.batteryLevel * 100))
}
}
Finally, complete the setMethodCallHandler
method added earlier. You need to handle a single platform method, getBatteryLevel
, so test for that in the call
argument. The implementation of this platform method simply calls the iOS code written in the previous step. If an unknown method is called, report that instead.
batteryChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
guard call.method == "getBatteryLevel" else {
result(FlutterMethodNotImplemented)
return
}
self?.receiveBatteryLevel(result: result)
})
You should now be able to run the app on iOS. If you are using the iOS Simulator, note that it does not support battery APIs, and the app displays ‘Battery info unavailable.’.
Separate platform-specific code from UI code
If you expect to use your platform-specific code in multiple Flutter apps, it can be useful to separate the code into a platform plugin located in a directory outside your main application. See developing packages for details.
Publish platform-specific code as a package
If you wish to share your platform-specific with other developers in the Flutter ecosystem, please see publishing packages for details.
Custom channels and codecs
Besides the above mentioned MethodChannel
, you can also use the more plain BasicMessageChannel
, which supports basic, asynchronous message passing using a custom message codec. Further, you can use the specialized BinaryCodec
, StringCodec
, and JSONMessageCodec
classes, or create your own codec.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论