App Entry Point:

void main() {
  runWhat();}

void runWhat() async{

//getLoggedInSharedPrefs() gets logged in state from SharedPrefs
  await getLoggedInSharedPrefs().then((isLoggedIn) {
    if(isLoggedIn) {
      runApp(Home()); // User is Logged in go to Home; 
    } else {
      runApp(new MyApp()); // Login Screen - separate from Home
    }
  });
}

In Home, I want to alert User on pressing back and alert if they want to exit out of app. But neither _onWillPop nor dispose get called

Home is a separate screen from MyApp and is not the body of MyApp

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    HomeState homeState() => new HomeState();
    return homeState();
  }
}

class HomeState extends State<Home> {

    @override
    Widget build(BuildContext context) {
      return WillPopScope(
        onWillPop: _onWillPop,
         child: new MaterialApp(.....

    @override
      void dispose() {
        print('dispose: $this');
        super.dispose();
      }

     Future<bool> _onWillPop() {
        print("Poppoing Home on will popo");
        return showDialog(
              context: context,
              builder: (context) => new AlertDialog(
                    title: new Text('Home - Are you sure?'),
                    content: new Text('Do you want to exit'),
                    actions: <Widget>[
                      new FlatButton(
                        onPressed: () => Navigator.pop(context),
                        child: new Text('No'),
                      ),
                      new FlatButton(
                        onPressed: () => exit(0),
                        child: new Text('Yes'),
                      ),
                    ],
                  ),
            ) ??
            false;
      }

... }


Solution 1: soupjake

You need to rearrange how you've set up your app as in your WillPopScope should be within MaterialApp and Scaffold:

App Class

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        theme: ThemeData.dark(),
        home: Scaffold(
          body: HomePage(),
        ),
      );
  }
}

Your Page

import 'dart:async';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return new WillPopScope(
              onWillPop: _onWillPop,
               child:new Center(
              child: new Text("Home Page"),
            ),
          );
  }

  Future<bool> _onWillPop() {
    return showDialog(
          context: context,
          builder: (context) => new AlertDialog(
                title: new Text('Are you sure?'),
                content: new Text('Do you want to exit an App'),
                actions: <Widget>[
                  new FlatButton(
                    onPressed: () => Navigator.of(context).pop(false),
                    child: new Text('No'),
                  ),
                  new FlatButton(
                    onPressed: () => Navigator.of(context).pop(true),
                    child: new Text('Yes'),
                  ),
                ],
              ),
        ) ??
        false;
  }
}

Demo


Solution 2: John Ravi

Taking hint from @SnakeyHips I modified my code as below but I needed Scaffold to be stateful for tab navigation

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(fontFamily: 'Georgia'),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {

  ....

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: new WillPopScope(
    onWillPop: _onWillPop,
    .... 
  }

 }