preface

There are only a few ApiCloud Ionic Taro Flutter development projects I have used. The biggest reason why Flutter is my favorite is because I changed the language to Dart. I don’t mean to sound weird, but it is a strong type language

Why Flutter development

The biggest reason, then, is that executives believe that Android and ios incumbents are hard to recruit and expensive, and that web juniors are plentiful and cheap? Ha ha ha 😂 wry smile ing…… And then you step on the flutter from zero to zero.

Is it because the browser can print Hello World when it opens the Console?

Sometimes I wonder why the Web is so unpopular with front-end development!!

Start, start

Although I am not in charge of the front end of the company, I always like to be ahead of the curve when it comes to unfamiliar technologies

I spent three days to build the overall structure of the project, of course, I copied it from the online video.

I have used Flutter development before, because it was the first time, so I followed the official website without using any framework (Getx), etc. The development process was quite painful and different from other hybrid development.

Therefore, after gaining experience, the framework Getx is used in App development this time, which is similar to front-end Angular and Vue. Therefore, once the UI of Flutter is written well, other logic aspects are not difficult, because I think Dart and Javascript have many similarities. Of course, the Dart’s air safety is disgusting at first touch

Technology stack

Projects are developed using GetCli scaffolding, similar to Angular, which generates pages, routes, models, etc

dependencies:
  sp_util: ^ the 2.0.3
  dio: ^ 4.0.0
  intl: ^ 0.17.0
  video_player: ^ 2.2.5
  get: 4.38.
  xxtea: ^ 2.1.0
  murmurhash: ^ 1.0.0
  device_info_plus: ^ 3.1.0
  pull_to_refresh: ^ 2.0.0
  flutter_switch: 0.32.
  flutter_pickers: ^ 2.1.3
  webview_flutter: ^ 2.1.1
  flutter_datetime_picker: ^ 1.5.1
  url_launcher: 6.012.
  flutter_staggered_animations: ^ 1.0.0
  daydart: ^ 0.0.5
  qr_flutter: 4.0. 0
  screenshot: ^ 1.2.3
  image_gallery_saver: '^ 1.7.1'
  package_info_plus: ^ 1.3.0
  rxdart: ^ 0.27.2
  event_bus: ^ 2.0.0
Copy the code

The directory structure

  • App #GetCli automatically generates files through commands to generate pages, routes
  • Components # Store the common components of the page
  • HTTP # Dio-based Network request encapsulation, and data Model
  • Lang # internationalization
  • Middleware # Middleware used for Getx routing
  • Stream # Encapsulates StreamBuilder
  • Theme # Saves uniform colors, styles, font sizes, etc
  • Utils # utility functions

Project course

  1. useGetCliGenerating project
  2. useFlutterImgSync Plug-ins for project static resource generation, so that project images use aspects of the specification
  3. Based on theDioNetwork encapsulation, usexxetaEncrypt it if you don’t want to use itDio, can also quickly switch to other network request libraries
  4. Based on theGetx Specification to achieve internationalization of the package, the implementation of English and Simplified Chinese
  5. Using GetMiddleware to block unlogged pages and jump to a login page if you need permission, you can’t write asynchronous code, which is a pain, so you need to write more code to fix login failures.
  6. The BehaviorSubject of StreamBuilder is also called RxDart. Because the StreamBuilder only has a single listener, the performance of multiple listeners is not as good as I want. Therefore, rxDart provides unified project management. NoData, Error] status. Services only need to pay attention to the success status and it is easy to use
  7. Write common colors, font sizes, common styles (such as shadows, borders, etc.) to theme. The team is not very standardized, so there are not many common 😓
  8. Add color, font size, and other extensions to String and Number to make it easier to use the blue Lake properties
  9. Controller writes and stores data common to the whole project, such as token and userInfo

Problems encountered in the project

/// You need to call the following code before initializing the storage, or you will get an error
WidgetsFlutterBinding.ensureInitialized();
/// Initialize storage
await SpUtil.getInstance();
Copy the code
/// Replace the MaterialApp with GetMaterialApp
GetMaterialApp(
	home: HomePage(), // If you use the home property to initialize the page, the boot page may be blank
    initialRoute: Routes.HOME_PAGE // Initialize the page this way
)
Copy the code

When using TabBar and TabbarView with the page, sliding on mi 10 and OPPO phones will be stuck. The reason seems to be a sliding conflict problem

Using NestedScrollView will solve the problem of some phones getting stuck.

Special case handling using GetView

Get officials recommend that we use GetView as the outermost Widget on the page and say that StatefulWidget is rarely needed, but there are many cases where StatefulWidget is needed

  1. For example, to cache the state of the page [PageView switch, need to keep the page scroll state]
  2. The controller of get is not executing onInit, so use the StatefulWidget to initialize the page in initState.

Lessons learned

  1. Returning to the previous page requires some refreshing

    1. For example, [bankcard list -> Add bankcard] After adding the bankcard, we need to refresh the bankcard list, because the front end of the Web is written too much, we often operate the instances of other components, for example, Get.find() to find the instance of the bankcard list to update the page, of course, this looks no problem. The best way to return to the page is to use toNamed(“add-bank”).then to listen for the page to return. Implement the refresh operation internally. It’s best to do your own thing.
  2. Data Management issues

    1. If the data needs to be used by multiple pages, it is better to create a separate controller to store the data, not the controller of a single page.
  3. Custom implementation of global Loading

    1. At the beginning, I thought it was unnecessary to install a third-party plug-in for Loading, so I finished it by myself.

    2. OverlayEntry is used to complete the Loading effect, but the OverlayEntry needs to get the context to the page type, so we used this method to pass the context to the page type at first. Later, we found that some places could not get the context, so we looked at the implementation of other plug-ins. The navigatorKey of the MaterialApp can obtain the current context

      //main.dart
      // Create a global Key
      GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
      // Write to GetMaterialApp
      GetMaterialApp(
          navigatorKey: navigatorKey
      )
          
      // loading.dart
      // This method is used to de-contextualizenavigatorKey.currentState! .overlay! .insert()Copy the code
  4. App login often fails to solve various problems (self-perception is not correct ~~)

    1. Some pages require permissions to access, which can be solved using middleware
    2. If the project is a single login, can lead to use to be on the way, of course, if the socket links, it is easy to solve, the failure time amend the local login status, if there is no socket links, only when request interface to know whether the failure, if in the request to intercept failure of the operation, I’m going to go straight to the login page, and I’m going to go back to the previous page and if I want to refresh the page, it’s not very easy. There’s no perfect solution. Now we are using The EventBus scheme for notification, which is not very good!
  5. Dispose method dispose should be disposed in the onClose of the controller of Getx. I know it’s a little silly to say this, but it does. And the general situation does not report the error, but when reporting the error is very difficult to locate the problem, or to understand the life cycle is not thorough ah

  6. How to use RouteAware related hook functions

    // marin.dart
    RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
    
    GetMaterialApp(
    	navigatorObservers: [routeObserver]
    )
    Copy the code
    // Create a new file
    abstract class RouteAwareState<T extends StatefulWidget> extends State<T>
        with RouteAware {
      @override
      void didChangeDependencies() {
        print("didChangeDependencies $widget");
        routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute); //Subscribe it here
        super.didChangeDependencies();
      }
    
      @override
      void didPush() {
        print('didPush $widget');
      }
    
      @override
      void didPopNext() {
        print('didPopNext $widget');
      }
    
      @override
      void didPop() {
        print('didPop $widget');
      }
    
      @override
      void didPushNext() {
        print('didPushNext $widget');
      }
    
      @override
      void dispose() {
        print("dispose $widget");
        routeObserver.unsubscribe(this);
        super.dispose(); }}Copy the code
    Class MyView extends StatefulWidget {const MyView({Key? key}) : super(key: key); @override _MyViewState createState() => _MyViewState(); {RouteAwareState = RouteAwareState;} State class _MyViewState extends RouteAwareState<MyView> {@override Widget Build (BuildContext context) {return MyViewContent(); }}Copy the code

Plug-in amway

  1. FlutterImgSync makes it easy and uniform to use static images

  2. GetX quickly inserts getX-related widgets

  3. JsonToDart comes with a null-safe Model generation plug-in

  4. Flutter Snippets generate code Snippets quickly