应用的启动
应用启动方案
通常在应用启动时根据用户是否是第一次打开决定是直接进入应用还是进入引导页,本例中通过在应用中文件存储用户上次启动的应用版本以判断是否进入引导页
获取应用版本
引入 package_info
dependencies:
flutter:
sdk: flutter
package_info: ^0.3.2+1
读取版本信息
Future<Null> readAppVersion( then(String value))async{
PackageInfo info = await PackageInfo.fromPlatform();
then(info.version);
}
通过flutter与平台原生框架通信对版本号进行读写操作
这里我是使用ios自带的NSUserdefault做本地存储, 安卓也可自建一个json文件做一样的操作.
- 在ios项目中创建交互通道
创建方法
-(void)createChannelWithName:(NSString *)name :(FlutterMethodCallHandler _Nullable)handler{
//获取控制器
FlutterViewController *controller = (FlutterViewController * )self.window.rootViewController;
//创建通道
FlutterMethodChannel * appStartStateChannel = [FlutterMethodChannel methodChannelWithName:name binaryMessenger:controller];
[appStartStateChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
handler(call,result);
}];
}
使用方法
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
//添加读取userdefalut交互通道
[self createChannelWithName:@"samples.flutter.io/readUserDefaults" :^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if ([@"readUserDefaults" isEqualToString:call.method]) {
NSString *value = [[NSUserDefaults standardUserDefaults] valueForKey:[call.arguments valueForKey:@"key"]];
if (value.length > 0) {
result(value);
}else{
result(([FlutterError errorWithCode:@"UNAVAILABLE"
message:@"查询错误"
details:nil]));
}
}else{
result(FlutterMethodNotImplemented);
}
}];
//添加写入userdefalut交互通道
[self createChannelWithName:@"samples.flutter.io/setUserDefaults" :^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if ([@"setUserDefaults" isEqualToString:call.method]) {
[[NSUserDefaults standardUserDefaults] setValue:[call.arguments valueForKey:@"value"] forKey:[call.arguments valueForKey:@"key"]];
[[NSUserDefaults standardUserDefaults] synchronize];
result(@"success");
}else{
result(FlutterMethodNotImplemented);
}
}];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
这样,原生一侧读写userdefault的操作就准备好了.
- 在主项目中添加管理类管理读写操作
import 'package:flutter/services.dart';
import 'package:package_info/package_info.dart';
class HardwareIO {
factory HardwareIO() =>_getInstance();
static HardwareIO get instance => _getInstance();
static HardwareIO _instance;
HardwareIO._internal() {
}
static HardwareIO _getInstance() {
if (_instance == null) {
_instance = new HardwareIO._internal();
}
return _instance;
}
//创建读写通道
static const platformReadUserdefault = const MethodChannel('samples.flutter.io/readUserDefaults');
static const platformSetUserdefault = const MethodChannel('samples.flutter.io/setUserDefaults');
//向userdefault写入键值对
Future<Null> setUserDefault(String key,String value,then(String result)) async {
String result;
try {
result = await platformSetUserdefault.invokeMethod('setUserDefaults',{'key':key,'value':value});
} on PlatformException catch (e) {
result = "Failed to set.";
}
then(result);
}
//通过key从userdefault读取值
Future<Null> readUserDefault(String key ,then(String value)) async {
String result;
try {
result = await platformReadUserdefault.invokeMethod('readUserDefaults',{'key':key});
} on PlatformException catch (e) {
result = "Failed to read.";
}
then(result);
}
//读取应用版本
Future<Null> readAppVersion( then(String value))async{
PackageInfo info = await PackageInfo.fromPlatform();
then(info.version);
}
}
这样对于版本号读写的操作 就准备好了
应用的启动
- 给新项目一个新的空白启动页面(可以放上需要的加载页面)
- 在启动页面中读取版本信息,根据结果将加载页面替换为引导页或是主页
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:pjcj_flutter/Common/HardwareIO.dart';
//引导页
import 'LeadPage.dart';
//主页
import 'Root/RootPage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget with NavigatorObserver{
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
//应用启动入口
return new MaterialApp(
home: new MainApp(),
);
}
}
//加载页
class MainApp extends StatefulWidget{
_MainAppState createState() => new _MainAppState();
}
class _MainAppState extends State<MainApp> with WidgetsBindingObserver{
//加载页widget
Widget result = new Container(color: Colors.red,);
@override
void initState() {
//读取版本标记
HardwareIO.instance.readAppVersion((String version){
print(version);
HardwareIO.instance.readUserDefault('startInfo',
(String value){
//根据结果替换widget
if(value == 'alreadyOpen'+version){
setState(() {
result = new RootPage();
});
}else{
setState(() {
result = new LeadPage();
});
}
});
});
@override
Widget build(BuildContext context) {
return result;
}
}
如果你不喜欢直接替换widget的方式 也可以使用PUSH推出一个新的路由并禁用掉它的回退功能或者从栈中移除前方路由
我在从引导页进入主页时就是这么做的
推出一个新路由并移除之前的路由
Navigator.pushAndRemoveUntil(context, new MaterialPageRoute(builder: (context){return new RootPage();}), (Route<dynamic> route) => false,);
在一个路由中禁用掉回退方法
//在需要禁用回退方法的widget外包裹WillPopScope 并在onWillPop 中返回false
new WillPopScope(
child: new Container();
onWillPop: ()async{
return false;
});