Merge branch 'master' into update_nnbd
diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md
index b993bf1..60765d1 100644
--- a/packages/connectivity/connectivity/CHANGELOG.md
+++ b/packages/connectivity/connectivity/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 3.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 3.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 2.0.3
 
 * Update Flutter SDK constraint.
diff --git a/packages/connectivity/connectivity/analysis_options.yaml b/packages/connectivity/connectivity/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/connectivity/connectivity/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/connectivity/connectivity/example/lib/main.dart b/packages/connectivity/connectivity/example/lib/main.dart
index e054971..19285ce 100644
--- a/packages/connectivity/connectivity/example/lib/main.dart
+++ b/packages/connectivity/connectivity/example/lib/main.dart
@@ -40,7 +40,7 @@
 }
 
 class MyHomePage extends StatefulWidget {
-  MyHomePage({Key key, this.title}) : super(key: key);
+  MyHomePage({Key? key, required this.title}) : super(key: key);
 
   final String title;
 
@@ -51,7 +51,7 @@
 class _MyHomePageState extends State<MyHomePage> {
   String _connectionStatus = 'Unknown';
   final Connectivity _connectivity = Connectivity();
-  StreamSubscription<ConnectivityResult> _connectivitySubscription;
+  late StreamSubscription<ConnectivityResult> _connectivitySubscription;
 
   @override
   void initState() {
@@ -69,7 +69,7 @@
 
   // Platform messages are asynchronous, so we initialize in an async method.
   Future<void> initConnectivity() async {
-    ConnectivityResult result;
+    ConnectivityResult result = ConnectivityResult.none;
     // Platform messages may fail, so we use a try/catch PlatformException.
     try {
       result = await _connectivity.checkConnectivity();
diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml
index bff3548..94c8505 100644
--- a/packages/connectivity/connectivity/example/pubspec.yaml
+++ b/packages/connectivity/connectivity/example/pubspec.yaml
@@ -10,9 +10,10 @@
 dev_dependencies:
   flutter_driver:
     sdk: flutter
+  test: ^1.10.0-nullsafety.1
   integration_test:
     path: ../../../integration_test
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 flutter:
   uses-material-design: true
diff --git a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart
index d48deae..3177b66 100644
--- a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart
+++ b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed.
+// @dart = 2.9
+
 import 'package:integration_test/integration_test.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:connectivity/connectivity.dart';
diff --git a/packages/connectivity/connectivity/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/integration_test/connectivity_test.dart
index d48deae..3177b66 100644
--- a/packages/connectivity/connectivity/integration_test/connectivity_test.dart
+++ b/packages/connectivity/connectivity/integration_test/connectivity_test.dart
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed.
+// @dart = 2.9
+
 import 'package:integration_test/integration_test.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:connectivity/connectivity.dart';
diff --git a/packages/connectivity/connectivity/lib/connectivity.dart b/packages/connectivity/connectivity/lib/connectivity.dart
index c965536..0f30a93 100644
--- a/packages/connectivity/connectivity/lib/connectivity.dart
+++ b/packages/connectivity/connectivity/lib/connectivity.dart
@@ -22,12 +22,12 @@
     if (_singleton == null) {
       _singleton = Connectivity._();
     }
-    return _singleton;
+    return _singleton!;
   }
 
   Connectivity._();
 
-  static Connectivity _singleton;
+  static Connectivity? _singleton;
 
   static ConnectivityPlatform get _platform => ConnectivityPlatform.instance;
 
diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml
index 1a53f42..a22c137 100644
--- a/packages/connectivity/connectivity/pubspec.yaml
+++ b/packages/connectivity/connectivity/pubspec.yaml
@@ -2,7 +2,11 @@
 description: Flutter plugin for discovering the state of the network (WiFi &
   mobile/cellular) connectivity on Android and iOS.
 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity
+<<<<<<< HEAD
+version: 3.0.0-nullsafety.1
+=======
 version: 2.0.3
+>>>>>>> master
 
 flutter:
   plugin:
@@ -21,21 +25,24 @@
   flutter:
     sdk: flutter
   meta: ^1.0.5
-  connectivity_platform_interface: ^1.0.2
+  connectivity_platform_interface: 2.0.0-nullsafety.1
+  #TODO(cyanglaz): re-endorse the below plugins when they have migrated to nnbd.
+  # https://github.com/flutter/flutter/issues/68669
   connectivity_macos: ^0.1.0
-  connectivity_for_web: ^0.3.0
+  # connectivity_for_web: ^0.3.0
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
   flutter_driver:
     sdk: flutter
+  test: ^1.10.0-nullsafety.1
   integration_test:
     path: ../../integration_test
   mockito: ^4.1.1
-  plugin_platform_interface: ^1.0.0
-  pedantic: ^1.8.0
+  plugin_platform_interface: ^1.1.0-nullsafety.1
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.13+hotfix.5"
diff --git a/packages/connectivity/connectivity/test/connectivity_test.dart b/packages/connectivity/connectivity/test/connectivity_test.dart
index b7749ca..e831965 100644
--- a/packages/connectivity/connectivity/test/connectivity_test.dart
+++ b/packages/connectivity/connectivity/test/connectivity_test.dart
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
-
+// TODO(cyanglaz): Remove once Mockito is migrated to null safety.
+// @dart = 2.9
 import 'package:connectivity/connectivity.dart';
 import 'package:connectivity_platform_interface/connectivity_platform_interface.dart';
 import 'package:flutter_test/flutter_test.dart';
diff --git a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md
index 2a16860..8e38341 100644
--- a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md
+++ b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 2.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 1.0.7
 
 * Update Flutter SDK constraint.
diff --git a/packages/connectivity/connectivity_platform_interface/analysis_options.yaml b/packages/connectivity/connectivity_platform_interface/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart
index cfd9cf6..8e9f0fd 100644
--- a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart
+++ b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart
@@ -50,17 +50,17 @@
   }
 
   /// Obtains the wifi name (SSID) of the connected network
-  Future<String> getWifiName() {
+  Future<String?> getWifiName() {
     throw UnimplementedError('getWifiName() has not been implemented.');
   }
 
   /// Obtains the wifi BSSID of the connected network.
-  Future<String> getWifiBSSID() {
+  Future<String?> getWifiBSSID() {
     throw UnimplementedError('getWifiBSSID() has not been implemented.');
   }
 
   /// Obtains the IP address of the connected wifi network
-  Future<String> getWifiIP() {
+  Future<String?> getWifiIP() {
     throw UnimplementedError('getWifiIP() has not been implemented.');
   }
 
diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart
index 87deaa2..b411b5b 100644
--- a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart
+++ b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart
@@ -22,29 +22,29 @@
   EventChannel eventChannel =
       EventChannel('plugins.flutter.io/connectivity_status');
 
-  Stream<ConnectivityResult> _onConnectivityChanged;
+  Stream<ConnectivityResult>? _onConnectivityChanged;
 
   /// Fires whenever the connectivity state changes.
   Stream<ConnectivityResult> get onConnectivityChanged {
     if (_onConnectivityChanged == null) {
-      _onConnectivityChanged = eventChannel
-          .receiveBroadcastStream()
-          .map((dynamic result) => result.toString())
-          .map(parseConnectivityResult);
+      _onConnectivityChanged =
+          eventChannel.receiveBroadcastStream().map((dynamic result) {
+        return result != null ? result.toString() : '';
+      }).map(parseConnectivityResult);
     }
-    return _onConnectivityChanged;
+    return _onConnectivityChanged!;
   }
 
   @override
-  Future<ConnectivityResult> checkConnectivity() {
-    return methodChannel
-        .invokeMethod<String>('check')
-        .then(parseConnectivityResult);
+  Future<ConnectivityResult> checkConnectivity() async {
+    final String checkResult =
+        await methodChannel.invokeMethod<String>('check') ?? '';
+    return parseConnectivityResult(checkResult);
   }
 
   @override
-  Future<String> getWifiName() async {
-    String wifiName = await methodChannel.invokeMethod<String>('wifiName');
+  Future<String?> getWifiName() async {
+    String? wifiName = await methodChannel.invokeMethod<String>('wifiName');
     // as Android might return <unknown ssid>, uniforming result
     // our iOS implementation will return null
     if (wifiName == '<unknown ssid>') {
@@ -54,29 +54,31 @@
   }
 
   @override
-  Future<String> getWifiBSSID() {
+  Future<String?> getWifiBSSID() {
     return methodChannel.invokeMethod<String>('wifiBSSID');
   }
 
   @override
-  Future<String> getWifiIP() {
+  Future<String?> getWifiIP() {
     return methodChannel.invokeMethod<String>('wifiIPAddress');
   }
 
   @override
   Future<LocationAuthorizationStatus> requestLocationServiceAuthorization({
     bool requestAlwaysLocationUsage = false,
-  }) {
-    return methodChannel.invokeMethod<String>(
-        'requestLocationServiceAuthorization', <bool>[
-      requestAlwaysLocationUsage
-    ]).then(parseLocationAuthorizationStatus);
+  }) async {
+    final String requestLocationServiceResult = await methodChannel
+            .invokeMethod<String>('requestLocationServiceAuthorization',
+                <bool>[requestAlwaysLocationUsage]) ??
+        '';
+    return parseLocationAuthorizationStatus(requestLocationServiceResult);
   }
 
   @override
-  Future<LocationAuthorizationStatus> getLocationServiceAuthorization() {
-    return methodChannel
-        .invokeMethod<String>('getLocationServiceAuthorization')
-        .then(parseLocationAuthorizationStatus);
+  Future<LocationAuthorizationStatus> getLocationServiceAuthorization() async {
+    final String getLocationServiceResult = await methodChannel
+            .invokeMethod<String>('getLocationServiceAuthorization') ??
+        '';
+    return parseLocationAuthorizationStatus(getLocationServiceResult);
   }
 }
diff --git a/packages/connectivity/connectivity_platform_interface/pubspec.yaml b/packages/connectivity/connectivity_platform_interface/pubspec.yaml
index 7aa415c..114915a 100644
--- a/packages/connectivity/connectivity_platform_interface/pubspec.yaml
+++ b/packages/connectivity/connectivity_platform_interface/pubspec.yaml
@@ -3,19 +3,19 @@
 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.0.7
+version: 2.0.0-nullsafety.1
 
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.0.5
-  plugin_platform_interface: ^1.0.1
+  meta: ^1.3.0-nullsafety.3
+  plugin_platform_interface: ^1.1.0-nullsafety.1
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.13+hotfix.5"
diff --git a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart
index 3d9c405..0c30530 100644
--- a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart
+++ b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart
@@ -12,7 +12,7 @@
 
   group('$MethodChannelConnectivity', () {
     final List<MethodCall> log = <MethodCall>[];
-    MethodChannelConnectivity methodChannelConnectivity;
+    late MethodChannelConnectivity methodChannelConnectivity;
 
     setUp(() async {
       methodChannelConnectivity = MethodChannelConnectivity();
@@ -42,7 +42,7 @@
           .setMockMethodCallHandler((MethodCall methodCall) async {
         switch (methodCall.method) {
           case 'listen':
-            await ServicesBinding.instance.defaultBinaryMessenger
+            await ServicesBinding.instance!.defaultBinaryMessenger
                 .handlePlatformMessage(
               methodChannelConnectivity.eventChannel.name,
               methodChannelConnectivity.eventChannel.codec
@@ -64,7 +64,7 @@
     });
 
     test('getWifiName', () async {
-      final String result = await methodChannelConnectivity.getWifiName();
+      final String? result = await methodChannelConnectivity.getWifiName();
       expect(result, '1337wifi');
       expect(
         log,
@@ -78,7 +78,7 @@
     });
 
     test('getWifiBSSID', () async {
-      final String result = await methodChannelConnectivity.getWifiBSSID();
+      final String? result = await methodChannelConnectivity.getWifiBSSID();
       expect(result, 'c0:ff:33:c0:d3:55');
       expect(
         log,
@@ -92,7 +92,7 @@
     });
 
     test('getWifiIP', () async {
-      final String result = await methodChannelConnectivity.getWifiIP();
+      final String? result = await methodChannelConnectivity.getWifiIP();
       expect(result, '127.0.0.1');
       expect(
         log,
diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md
index 29382c1..cee3217 100644
--- a/packages/device_info/device_info/CHANGELOG.md
+++ b/packages/device_info/device_info/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 2.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 1.0.1
 
 * Update Flutter SDK constraint.
diff --git a/packages/device_info/device_info/analysis_options.yaml b/packages/device_info/device_info/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/device_info/device_info/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/device_info/device_info/example/integration_test/device_info_test.dart b/packages/device_info/device_info/example/integration_test/device_info_test.dart
index 2fd1d9a..61c4396 100644
--- a/packages/device_info/device_info/example/integration_test/device_info_test.dart
+++ b/packages/device_info/device_info/example/integration_test/device_info_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed.
+// @dart = 2.9
+
 import 'dart:io';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:device_info/device_info.dart';
diff --git a/packages/device_info/device_info/example/lib/main.dart b/packages/device_info/device_info/example/lib/main.dart
index 63912b3..805de14 100644
--- a/packages/device_info/device_info/example/lib/main.dart
+++ b/packages/device_info/device_info/example/lib/main.dart
@@ -36,7 +36,7 @@
   }
 
   Future<void> initPlatformState() async {
-    Map<String, dynamic> deviceData;
+    Map<String, dynamic> deviceData = <String, dynamic>{};
 
     try {
       if (Platform.isAndroid) {
diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml
index 58d54cb..09567fd 100644
--- a/packages/device_info/device_info/example/pubspec.yaml
+++ b/packages/device_info/device_info/example/pubspec.yaml
@@ -12,11 +12,11 @@
     sdk: flutter
   integration_test:
     path: ../../../integration_test
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 flutter:
   uses-material-design: true
 
 environment:
-  sdk: ">=2.1.0<3.0.0"
+  sdk: ">=2.10.0-56.0.dev <3.0.0"
   flutter: ">=1.12.13+hotfix.5 <2.0.0"
diff --git a/packages/device_info/device_info/example/test_driver/integration_test.dart b/packages/device_info/device_info/example/test_driver/integration_test.dart
index 7a2c213..13327bb 100644
--- a/packages/device_info/device_info/example/test_driver/integration_test.dart
+++ b/packages/device_info/device_info/example/test_driver/integration_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed.
+// @dart = 2.9
+
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
diff --git a/packages/device_info/device_info/lib/device_info.dart b/packages/device_info/device_info/lib/device_info.dart
index f63730c..bccc3d2 100644
--- a/packages/device_info/device_info/lib/device_info.dart
+++ b/packages/device_info/device_info/lib/device_info.dart
@@ -15,7 +15,7 @@
   DeviceInfoPlugin();
 
   /// This information does not change from call to call. Cache it.
-  AndroidDeviceInfo _cachedAndroidDeviceInfo;
+  AndroidDeviceInfo? _cachedAndroidDeviceInfo;
 
   /// Information derived from `android.os.Build`.
   ///
@@ -25,7 +25,7 @@
           await DeviceInfoPlatform.instance.androidInfo();
 
   /// This information does not change from call to call. Cache it.
-  IosDeviceInfo _cachedIosDeviceInfo;
+  IosDeviceInfo? _cachedIosDeviceInfo;
 
   /// Information derived from `UIDevice`.
   ///
diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml
index 0f31234..fccfe2f 100644
--- a/packages/device_info/device_info/pubspec.yaml
+++ b/packages/device_info/device_info/pubspec.yaml
@@ -2,7 +2,14 @@
 description: Flutter plugin providing detailed information about the device
   (make, model, etc.), and Android or iOS version the app is running on.
 homepage: https://github.com/flutter/plugins/tree/master/packages/device_info
+<<<<<<< HEAD
+# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump
+# the version to 2.0.0.
+# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
+version: 2.0.0-nullsafety.1
+=======
 version: 1.0.1
+>>>>>>> master
 
 flutter:
   plugin:
@@ -16,14 +23,13 @@
 dependencies:
   flutter:
     sdk: flutter
-  device_info_platform_interface: ^1.0.0
-
+  device_info_platform_interface: ^2.0.0-nullsafety.1
 dev_dependencies:
-  test: ^1.3.0
+  test: ^1.10.0-nullsafety.1
   flutter_test:
     sdk: flutter
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0<3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.13+hotfix.5"
diff --git a/packages/device_info/device_info_platform_interface/CHANGELOG.md b/packages/device_info/device_info_platform_interface/CHANGELOG.md
index e513c66..d4bc81e 100644
--- a/packages/device_info/device_info_platform_interface/CHANGELOG.md
+++ b/packages/device_info/device_info_platform_interface/CHANGELOG.md
@@ -1,3 +1,16 @@
+## 2.0.0-nullsafety.2
+
+* Make `baseOS`, `previewSdkInt`, and `securityPatch` nullable types.
+* Remove default values for non-nullable types.
+
+## 2.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 1.0.2
 
 - Update Flutter SDK constraint.
diff --git a/packages/device_info/device_info_platform_interface/analysis_options.yaml b/packages/device_info/device_info_platform_interface/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/device_info/device_info_platform_interface/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart
index 5b326cc..4fb940c 100644
--- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart
+++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart
@@ -8,28 +8,28 @@
 class AndroidDeviceInfo {
   /// Android device Info class.
   AndroidDeviceInfo({
-    this.version,
-    this.board,
-    this.bootloader,
-    this.brand,
-    this.device,
-    this.display,
-    this.fingerprint,
-    this.hardware,
-    this.host,
-    this.id,
-    this.manufacturer,
-    this.model,
-    this.product,
-    List<String> supported32BitAbis,
-    List<String> supported64BitAbis,
-    List<String> supportedAbis,
-    this.tags,
-    this.type,
-    this.isPhysicalDevice,
-    this.androidId,
-    List<String> systemFeatures,
-  })  : supported32BitAbis = List<String>.unmodifiable(supported32BitAbis),
+    required this.version,
+    required this.board,
+    required this.bootloader,
+    required this.brand,
+    required this.device,
+    required this.display,
+    required this.fingerprint,
+    required this.hardware,
+    required this.host,
+    required this.id,
+    required this.manufacturer,
+    required this.model,
+    required this.product,
+    required List<String> supported32BitAbis,
+    required List<String> supported64BitAbis,
+    required List<String> supportedAbis,
+    required this.tags,
+    required this.type,
+    required this.isPhysicalDevice,
+    required this.androidId,
+    required List<String> systemFeatures,
+  })   : supported32BitAbis = List<String>.unmodifiable(supported32BitAbis),
         supported64BitAbis = List<String>.unmodifiable(supported64BitAbis),
         supportedAbis = List<String>.unmodifiable(supportedAbis),
         systemFeatures = List<String>.unmodifiable(systemFeatures);
@@ -113,28 +113,28 @@
   /// Deserializes from the message received from [_kChannel].
   static AndroidDeviceInfo fromMap(Map<String, dynamic> map) {
     return AndroidDeviceInfo(
-      version: AndroidBuildVersion._fromMap(
-          map['version']?.cast<String, dynamic>() ?? {}),
-      board: map['board'],
-      bootloader: map['bootloader'],
-      brand: map['brand'],
-      device: map['device'],
-      display: map['display'],
-      fingerprint: map['fingerprint'],
-      hardware: map['hardware'],
-      host: map['host'],
-      id: map['id'],
-      manufacturer: map['manufacturer'],
-      model: map['model'],
-      product: map['product'],
-      supported32BitAbis: _fromList(map['supported32BitAbis'] ?? []),
-      supported64BitAbis: _fromList(map['supported64BitAbis'] ?? []),
-      supportedAbis: _fromList(map['supportedAbis'] ?? []),
-      tags: map['tags'],
-      type: map['type'],
-      isPhysicalDevice: map['isPhysicalDevice'],
-      androidId: map['androidId'],
-      systemFeatures: _fromList(map['systemFeatures'] ?? []),
+      version:
+          AndroidBuildVersion._fromMap(map['version']!.cast<String, dynamic>()),
+      board: map['board']!,
+      bootloader: map['bootloader']!,
+      brand: map['brand']!,
+      device: map['device']!,
+      display: map['display']!,
+      fingerprint: map['fingerprint']!,
+      hardware: map['hardware']!,
+      host: map['host']!,
+      id: map['id']!,
+      manufacturer: map['manufacturer']!,
+      model: map['model']!,
+      product: map['product']!,
+      supported32BitAbis: _fromList(map['supported32BitAbis']!),
+      supported64BitAbis: _fromList(map['supported64BitAbis']!),
+      supportedAbis: _fromList(map['supportedAbis']!),
+      tags: map['tags']!,
+      type: map['type']!,
+      isPhysicalDevice: map['isPhysicalDevice']!,
+      androidId: map['androidId']!,
+      systemFeatures: _fromList(map['systemFeatures']!),
     );
   }
 
@@ -152,16 +152,25 @@
 class AndroidBuildVersion {
   AndroidBuildVersion._({
     this.baseOS,
-    this.codename,
-    this.incremental,
     this.previewSdkInt,
-    this.release,
-    this.sdkInt,
     this.securityPatch,
+    required this.codename,
+    required this.incremental,
+    required this.release,
+    required this.sdkInt,
   });
 
   /// The base OS build the product is based on.
-  final String baseOS;
+  /// This is only available on Android 6.0 or above.
+  String? baseOS;
+
+  /// The developer preview revision of a prerelease SDK.
+  /// This is only available on Android 6.0 or above.
+  int? previewSdkInt;
+
+  /// The user-visible security patch level.
+  /// This is only available on Android 6.0 or above.
+  final String? securityPatch;
 
   /// The current development codename, or the string "REL" if this is a release build.
   final String codename;
@@ -169,9 +178,6 @@
   /// The internal value used by the underlying source control to represent this build.
   final String incremental;
 
-  /// The developer preview revision of a prerelease SDK.
-  final int previewSdkInt;
-
   /// The user-visible version string.
   final String release;
 
@@ -180,19 +186,16 @@
   /// Possible values are defined in: https://developer.android.com/reference/android/os/Build.VERSION_CODES.html
   final int sdkInt;
 
-  /// The user-visible security patch level.
-  final String securityPatch;
-
   /// Deserializes from the map message received from [_kChannel].
   static AndroidBuildVersion _fromMap(Map<String, dynamic> map) {
     return AndroidBuildVersion._(
       baseOS: map['baseOS'],
-      codename: map['codename'],
-      incremental: map['incremental'],
       previewSdkInt: map['previewSdkInt'],
-      release: map['release'],
-      sdkInt: map['sdkInt'],
       securityPatch: map['securityPatch'],
+      codename: map['codename']!,
+      incremental: map['incremental']!,
+      release: map['release']!,
+      sdkInt: map['sdkInt']!,
     );
   }
 }
diff --git a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart
index d412024..eb6e587 100644
--- a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart
+++ b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart
@@ -8,14 +8,14 @@
 class IosDeviceInfo {
   /// IOS device info class.
   IosDeviceInfo({
-    this.name,
-    this.systemName,
-    this.systemVersion,
-    this.model,
-    this.localizedModel,
-    this.identifierForVendor,
-    this.isPhysicalDevice,
-    this.utsname,
+    required this.name,
+    required this.systemName,
+    required this.systemVersion,
+    required this.model,
+    required this.localizedModel,
+    required this.identifierForVendor,
+    required this.isPhysicalDevice,
+    required this.utsname,
   });
 
   /// Device name.
@@ -45,15 +45,14 @@
   /// Deserializes from the map message received from [_kChannel].
   static IosDeviceInfo fromMap(Map<String, dynamic> map) {
     return IosDeviceInfo(
-      name: map['name'],
-      systemName: map['systemName'],
-      systemVersion: map['systemVersion'],
-      model: map['model'],
-      localizedModel: map['localizedModel'],
-      identifierForVendor: map['identifierForVendor'],
+      name: map['name']!,
+      systemName: map['systemName']!,
+      systemVersion: map['systemVersion']!,
+      model: map['model']!,
+      localizedModel: map['localizedModel']!,
+      identifierForVendor: map['identifierForVendor']!,
       isPhysicalDevice: map['isPhysicalDevice'] == 'true',
-      utsname:
-          IosUtsname._fromMap(map['utsname']?.cast<String, dynamic>() ?? {}),
+      utsname: IosUtsname._fromMap(map['utsname']!.cast<String, dynamic>()),
     );
   }
 }
@@ -62,11 +61,11 @@
 /// See http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html for details.
 class IosUtsname {
   IosUtsname._({
-    this.sysname,
-    this.nodename,
-    this.release,
-    this.version,
-    this.machine,
+    required this.sysname,
+    required this.nodename,
+    required this.release,
+    required this.version,
+    required this.machine,
   });
 
   /// Operating system name.
@@ -87,11 +86,11 @@
   /// Deserializes from the map message received from [_kChannel].
   static IosUtsname _fromMap(Map<String, dynamic> map) {
     return IosUtsname._(
-      sysname: map['sysname'],
-      nodename: map['nodename'],
-      release: map['release'],
-      version: map['version'],
-      machine: map['machine'],
+      sysname: map['sysname']!,
+      nodename: map['nodename']!,
+      release: map['release']!,
+      version: map['version']!,
+      machine: map['machine']!,
     );
   }
 }
diff --git a/packages/device_info/device_info_platform_interface/pubspec.yaml b/packages/device_info/device_info_platform_interface/pubspec.yaml
index fedaba6..ca72cc7 100644
--- a/packages/device_info/device_info_platform_interface/pubspec.yaml
+++ b/packages/device_info/device_info_platform_interface/pubspec.yaml
@@ -3,20 +3,20 @@
 homepage: https://github.com/flutter/plugins/tree/master/packages/device_info
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.0.2
+version: 2.0.0-nullsafety.2
 
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.1.8
-  plugin_platform_interface: ^1.0.2
+  meta: ^1.3.0-nullsafety.3
+  plugin_platform_interface: ^1.1.0-nullsafety.1
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  mockito: ^4.1.1
-  pedantic: ^1.8.0
+  test: ^1.10.0-nullsafety.1
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.7.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.9.1+hotfix.4"
diff --git a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart
index 1da52e2..1596385 100644
--- a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart
+++ b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed.
+// @dart = 2.9
+
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
-
 import 'package:device_info_platform_interface/device_info_platform_interface.dart';
-
 import 'package:device_info_platform_interface/method_channel/method_channel_device_info.dart';
 
 void main() {
@@ -23,11 +24,68 @@
         switch (methodCall.method) {
           case 'getAndroidDeviceInfo':
             return ({
-              "brand": "Google",
+              "version": <String, dynamic>{
+                "securityPatch": "2018-09-05",
+                "sdkInt": 28,
+                "release": "9",
+                "previewSdkInt": 0,
+                "incremental": "5124027",
+                "codename": "REL",
+                "baseOS": "",
+              },
+              "board": "goldfish_x86_64",
+              "bootloader": "unknown",
+              "brand": "google",
+              "device": "generic_x86_64",
+              "display": "PSR1.180720.075",
+              "fingerprint":
+                  "google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys",
+              "hardware": "ranchu",
+              "host": "abfarm730",
+              "id": "PSR1.180720.075",
+              "manufacturer": "Google",
+              "model": "Android SDK built for x86_64",
+              "product": "sdk_gphone_x86_64",
+              "supported32BitAbis": <String>[
+                "x86",
+              ],
+              "supported64BitAbis": <String>[
+                "x86_64",
+              ],
+              "supportedAbis": <String>[
+                "x86_64",
+                "x86",
+              ],
+              "tags": "release-keys",
+              "type": "user",
+              "isPhysicalDevice": false,
+              "androidId": "f47571f3b4648f45",
+              "systemFeatures": <String>[
+                "android.hardware.sensor.proximity",
+                "android.software.adoptable_storage",
+                "android.hardware.sensor.accelerometer",
+                "android.hardware.faketouch",
+                "android.software.backup",
+                "android.hardware.touchscreen",
+              ],
             });
           case 'getIosDeviceInfo':
             return ({
-              "name": "iPhone 10",
+              "name": "iPhone 13",
+              "systemName": "iOS",
+              "systemVersion": "13.0",
+              "model": "iPhone",
+              "localizedModel": "iPhone",
+              "identifierForVendor": "88F59280-55AD-402C-B922-3203B4794C06",
+              "isPhysicalDevice": false,
+              "utsname": <String, dynamic>{
+                "sysname": "Darwin",
+                "nodename": "host",
+                "release": "19.6.0",
+                "version":
+                    "Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64",
+                "machine": "x86_64",
+              }
             });
           default:
             return null;
@@ -38,12 +96,66 @@
     test("androidInfo", () async {
       final AndroidDeviceInfo result =
           await methodChannelDeviceInfo.androidInfo();
-      expect(result.brand, "Google");
+
+      expect(result.version.securityPatch, "2018-09-05");
+      expect(result.version.sdkInt, 28);
+      expect(result.version.release, "9");
+      expect(result.version.previewSdkInt, 0);
+      expect(result.version.incremental, "5124027");
+      expect(result.version.codename, "REL");
+      expect(result.board, "goldfish_x86_64");
+      expect(result.bootloader, "unknown");
+      expect(result.brand, "google");
+      expect(result.device, "generic_x86_64");
+      expect(result.display, "PSR1.180720.075");
+      expect(result.fingerprint,
+          "google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys");
+      expect(result.hardware, "ranchu");
+      expect(result.host, "abfarm730");
+      expect(result.id, "PSR1.180720.075");
+      expect(result.manufacturer, "Google");
+      expect(result.model, "Android SDK built for x86_64");
+      expect(result.product, "sdk_gphone_x86_64");
+      expect(result.supported32BitAbis, <String>[
+        "x86",
+      ]);
+      expect(result.supported64BitAbis, <String>[
+        "x86_64",
+      ]);
+      expect(result.supportedAbis, <String>[
+        "x86_64",
+        "x86",
+      ]);
+      expect(result.tags, "release-keys");
+      expect(result.type, "user");
+      expect(result.isPhysicalDevice, false);
+      expect(result.androidId, "f47571f3b4648f45");
+      expect(result.systemFeatures, <String>[
+        "android.hardware.sensor.proximity",
+        "android.software.adoptable_storage",
+        "android.hardware.sensor.accelerometer",
+        "android.hardware.faketouch",
+        "android.software.backup",
+        "android.hardware.touchscreen",
+      ]);
     });
 
     test("iosInfo", () async {
       final IosDeviceInfo result = await methodChannelDeviceInfo.iosInfo();
-      expect(result.name, "iPhone 10");
+      expect(result.name, "iPhone 13");
+      expect(result.systemName, "iOS");
+      expect(result.systemVersion, "13.0");
+      expect(result.model, "iPhone");
+      expect(result.localizedModel, "iPhone");
+      expect(
+          result.identifierForVendor, "88F59280-55AD-402C-B922-3203B4794C06");
+      expect(result.isPhysicalDevice, false);
+      expect(result.utsname.sysname, "Darwin");
+      expect(result.utsname.nodename, "host");
+      expect(result.utsname.release, "19.6.0");
+      expect(result.utsname.version,
+          "Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64");
+      expect(result.utsname.machine, "x86_64");
     });
   });
 }
diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart
index bc70919..7305800 100755
--- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart
+++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
+// @dart = 2.9
 
 import 'dart:async';
 
diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md
index 0ea59f3..d83798a 100644
--- a/packages/local_auth/CHANGELOG.md
+++ b/packages/local_auth/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 0.6.3+5
 
 * Update Flutter SDK constraint.
diff --git a/packages/local_auth/lib/auth_strings.dart b/packages/local_auth/lib/auth_strings.dart
index a8f34f8..3afc238 100644
--- a/packages/local_auth/lib/auth_strings.dart
+++ b/packages/local_auth/lib/auth_strings.dart
@@ -25,14 +25,14 @@
     this.goToSettingsDescription,
   });
 
-  final String fingerprintHint;
-  final String fingerprintNotRecognized;
-  final String fingerprintSuccess;
-  final String cancelButton;
-  final String signInTitle;
-  final String fingerprintRequiredTitle;
-  final String goToSettingsButton;
-  final String goToSettingsDescription;
+  final String? fingerprintHint;
+  final String? fingerprintNotRecognized;
+  final String? fingerprintSuccess;
+  final String? cancelButton;
+  final String? signInTitle;
+  final String? fingerprintRequiredTitle;
+  final String? goToSettingsButton;
+  final String? goToSettingsDescription;
 
   Map<String, String> get args {
     return <String, String>{
@@ -62,10 +62,10 @@
     this.cancelButton,
   });
 
-  final String lockOut;
-  final String goToSettingsButton;
-  final String goToSettingsDescription;
-  final String cancelButton;
+  final String? lockOut;
+  final String? goToSettingsButton;
+  final String? goToSettingsDescription;
+  final String? cancelButton;
 
   Map<String, String> get args {
     return <String, String>{
diff --git a/packages/local_auth/lib/local_auth.dart b/packages/local_auth/lib/local_auth.dart
index b2b03b9..f1dbdd4 100644
--- a/packages/local_auth/lib/local_auth.dart
+++ b/packages/local_auth/lib/local_auth.dart
@@ -67,7 +67,7 @@
   /// [PlatformException] with error code [otherOperatingSystem] on the iOS
   /// simulator.
   Future<bool> authenticateWithBiometrics({
-    @required String localizedReason,
+    required String localizedReason,
     bool useErrorDialogs = true,
     bool stickyAuth = false,
     AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(),
@@ -92,8 +92,9 @@
               'operating systems.',
           details: 'Your operating system is ${_platform.operatingSystem}');
     }
-    return await _channel.invokeMethod<bool>(
-        'authenticateWithBiometrics', args);
+    final bool? result =
+        await _channel.invokeMethod<bool>('authenticateWithBiometrics', args);
+    return result!;
   }
 
   /// Returns true if auth was cancelled successfully.
@@ -101,18 +102,20 @@
   /// Returns false if there was some error or no auth in progress.
   ///
   /// Returns [Future] bool true or false:
-  Future<bool> stopAuthentication() {
+  Future<bool> stopAuthentication() async {
     if (_platform.isAndroid) {
-      return _channel.invokeMethod<bool>('stopAuthentication');
+      final bool? result =
+          await _channel.invokeMethod<bool>('stopAuthentication');
+      return result!;
     }
-    return Future<bool>.sync(() => true);
+    return true;
   }
 
   /// Returns true if device is capable of checking biometrics
   ///
   /// Returns a [Future] bool true or false:
   Future<bool> get canCheckBiometrics async =>
-      (await _channel.invokeListMethod<String>('getAvailableBiometrics'))
+      (await _channel.invokeListMethod<String>('getAvailableBiometrics'))!
           .isNotEmpty;
 
   /// Returns a list of enrolled biometrics
@@ -122,10 +125,10 @@
   /// - BiometricType.fingerprint
   /// - BiometricType.iris (not yet implemented)
   Future<List<BiometricType>> getAvailableBiometrics() async {
-    final List<String> result =
-        (await _channel.invokeListMethod<String>('getAvailableBiometrics'));
+    final List<String>? result =
+        await _channel.invokeListMethod<String>('getAvailableBiometrics');
     final List<BiometricType> biometrics = <BiometricType>[];
-    result.forEach((String value) {
+    result!.forEach((String value) {
       switch (value) {
         case 'face':
           biometrics.add(BiometricType.face);
diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml
index 834980b..90f82da 100644
--- a/packages/local_auth/pubspec.yaml
+++ b/packages/local_auth/pubspec.yaml
@@ -16,8 +16,8 @@
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.0.5
-  intl: ">=0.15.1 <0.17.0"
+  meta: ^1.3.0-nullsafety.3
+  intl: ^0.17.0-nullsafety.2
   platform: ">=2.0.0 <4.0.0"
   flutter_plugin_android_lifecycle: ^1.0.2
 
@@ -28,8 +28,8 @@
     sdk: flutter
   flutter_test:
     sdk: flutter
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.13+hotfix.5"
diff --git a/packages/local_auth/test/local_auth_test.dart b/packages/local_auth/test/local_auth_test.dart
index 205c5f7..52b8dbf 100644
--- a/packages/local_auth/test/local_auth_test.dart
+++ b/packages/local_auth/test/local_auth_test.dart
@@ -19,7 +19,7 @@
     );
 
     final List<MethodCall> log = <MethodCall>[];
-    LocalAuthentication localAuthentication;
+    late LocalAuthentication localAuthentication;
 
     setUp(() {
       channel.setMockMethodCallHandler((MethodCall methodCall) {
diff --git a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md
index 47e4fee..9712126 100644
--- a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md
+++ b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 1.0.5
 
 * Update Flutter SDK constraint.
diff --git a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart
index 4f796aa..1ff2a97 100644
--- a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart
+++ b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart
@@ -40,26 +40,26 @@
 
   /// Path to the temporary directory on the device that is not backed up and is
   /// suitable for storing caches of downloaded files.
-  Future<String> getTemporaryPath() {
+  Future<String?> getTemporaryPath() {
     throw UnimplementedError('getTemporaryPath() has not been implemented.');
   }
 
   /// Path to a directory where the application may place application support
   /// files.
-  Future<String> getApplicationSupportPath() {
+  Future<String?> getApplicationSupportPath() {
     throw UnimplementedError(
         'getApplicationSupportPath() has not been implemented.');
   }
 
   /// Path to the directory where application can store files that are persistent,
   /// backed up, and not visible to the user, such as sqlite.db.
-  Future<String> getLibraryPath() {
+  Future<String?> getLibraryPath() {
     throw UnimplementedError('getLibraryPath() has not been implemented.');
   }
 
   /// Path to a directory where the application may place data that is
   /// user-generated, or that cannot otherwise be recreated by your application.
-  Future<String> getApplicationDocumentsPath() {
+  Future<String?> getApplicationDocumentsPath() {
     throw UnimplementedError(
         'getApplicationDocumentsPath() has not been implemented.');
   }
@@ -67,7 +67,7 @@
   /// Path to a directory where the application may access top level storage.
   /// The current operating system should be determined before issuing this
   /// function call, as this functionality is only available on Android.
-  Future<String> getExternalStoragePath() {
+  Future<String?> getExternalStoragePath() {
     throw UnimplementedError(
         'getExternalStoragePath() has not been implemented.');
   }
@@ -76,7 +76,7 @@
   /// stored. These paths typically reside on external storage like separate
   /// partitions or SD cards. Phones may have multiple storage directories
   /// available.
-  Future<List<String>> getExternalCachePaths() {
+  Future<List<String>?> getExternalCachePaths() {
     throw UnimplementedError(
         'getExternalCachePaths() has not been implemented.');
   }
@@ -84,10 +84,10 @@
   /// Paths to directories where application specific data can be stored.
   /// These paths typically reside on external storage like separate partitions
   /// or SD cards. Phones may have multiple storage directories available.
-  Future<List<String>> getExternalStoragePaths({
+  Future<List<String>?> getExternalStoragePaths({
     /// Optional parameter. See [StorageDirectory] for more informations on
     /// how this type translates to Android storage directories.
-    StorageDirectory type,
+    StorageDirectory? type,
   }) {
     throw UnimplementedError(
         'getExternalStoragePaths() has not been implemented.');
@@ -95,7 +95,7 @@
 
   /// Path to the directory where downloaded files can be stored.
   /// This is typically only relevant on desktop operating systems.
-  Future<String> getDownloadsPath() {
+  Future<String?> getDownloadsPath() {
     throw UnimplementedError('getDownloadsPath() has not been implemented.');
   }
 }
diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart
index 7826fa4..728c106 100644
--- a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart
+++ b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart
@@ -30,34 +30,34 @@
     _platform = platform;
   }
 
-  Future<String> getTemporaryPath() {
+  Future<String?> getTemporaryPath() {
     return methodChannel.invokeMethod<String>('getTemporaryDirectory');
   }
 
-  Future<String> getApplicationSupportPath() {
+  Future<String?> getApplicationSupportPath() {
     return methodChannel.invokeMethod<String>('getApplicationSupportDirectory');
   }
 
-  Future<String> getLibraryPath() {
+  Future<String?> getLibraryPath() {
     if (!_platform.isIOS && !_platform.isMacOS) {
       throw UnsupportedError('Functionality only available on iOS/macOS');
     }
     return methodChannel.invokeMethod<String>('getLibraryDirectory');
   }
 
-  Future<String> getApplicationDocumentsPath() {
+  Future<String?> getApplicationDocumentsPath() {
     return methodChannel
         .invokeMethod<String>('getApplicationDocumentsDirectory');
   }
 
-  Future<String> getExternalStoragePath() {
+  Future<String?> getExternalStoragePath() {
     if (!_platform.isAndroid) {
       throw UnsupportedError('Functionality only available on Android');
     }
     return methodChannel.invokeMethod<String>('getStorageDirectory');
   }
 
-  Future<List<String>> getExternalCachePaths() {
+  Future<List<String>?> getExternalCachePaths() {
     if (!_platform.isAndroid) {
       throw UnsupportedError('Functionality only available on Android');
     }
@@ -65,8 +65,8 @@
         .invokeListMethod<String>('getExternalCacheDirectories');
   }
 
-  Future<List<String>> getExternalStoragePaths({
-    StorageDirectory type,
+  Future<List<String>?> getExternalStoragePaths({
+    StorageDirectory? type,
   }) async {
     if (!_platform.isAndroid) {
       throw UnsupportedError('Functionality only available on Android');
@@ -77,7 +77,7 @@
     );
   }
 
-  Future<String> getDownloadsPath() {
+  Future<String?> getDownloadsPath() {
     if (!_platform.isMacOS) {
       throw UnsupportedError('Functionality only available on macOS');
     }
diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml
index fc3d469..59c1bf0 100644
--- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml
+++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml
@@ -3,20 +3,20 @@
 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.0.5
+version: 2.0.0-nullsafety
 
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.0.5
+  meta: ^1.3.0-nullsafety.3
   platform: ">=2.0.0 <4.0.0"
-  plugin_platform_interface: ^1.0.1
+  plugin_platform_interface: ^1.1.0-nullsafety
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.10.0"
diff --git a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart
index 99c9349..7130d77 100644
--- a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart
+++ b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart
@@ -19,7 +19,7 @@
   const String kDownloadsPath = 'downloadsPath';
 
   group('$MethodChannelPathProvider', () {
-    MethodChannelPathProvider methodChannelPathProvider;
+    late MethodChannelPathProvider methodChannelPathProvider;
     final List<MethodCall> log = <MethodCall>[];
 
     setUp(() async {
@@ -59,7 +59,7 @@
     });
 
     test('getTemporaryPath', () async {
-      final String path = await methodChannelPathProvider.getTemporaryPath();
+      final String? path = await methodChannelPathProvider.getTemporaryPath();
       expect(
         log,
         <Matcher>[isMethodCall('getTemporaryDirectory', arguments: null)],
@@ -68,7 +68,7 @@
     });
 
     test('getApplicationSupportPath', () async {
-      final String path =
+      final String? path =
           await methodChannelPathProvider.getApplicationSupportPath();
       expect(
         log,
@@ -92,7 +92,7 @@
       methodChannelPathProvider
           .setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios'));
 
-      final String path = await methodChannelPathProvider.getLibraryPath();
+      final String? path = await methodChannelPathProvider.getLibraryPath();
       expect(
         log,
         <Matcher>[isMethodCall('getLibraryDirectory', arguments: null)],
@@ -104,7 +104,7 @@
       methodChannelPathProvider
           .setMockPathProviderPlatform(FakePlatform(operatingSystem: 'macos'));
 
-      final String path = await methodChannelPathProvider.getLibraryPath();
+      final String? path = await methodChannelPathProvider.getLibraryPath();
       expect(
         log,
         <Matcher>[isMethodCall('getLibraryDirectory', arguments: null)],
@@ -113,7 +113,7 @@
     });
 
     test('getApplicationDocumentsPath', () async {
-      final String path =
+      final String? path =
           await methodChannelPathProvider.getApplicationDocumentsPath();
       expect(
         log,
@@ -125,13 +125,13 @@
     });
 
     test('getExternalCachePaths android succeeds', () async {
-      final List<String> result =
+      final List<String>? result =
           await methodChannelPathProvider.getExternalCachePaths();
       expect(
         log,
         <Matcher>[isMethodCall('getExternalCacheDirectories', arguments: null)],
       );
-      expect(result.length, 1);
+      expect(result!.length, 1);
       expect(result.first, kExternalCachePaths);
     });
 
@@ -147,10 +147,12 @@
       }
     });
 
-    for (StorageDirectory type
-        in StorageDirectory.values + <StorageDirectory>[null]) {
+    for (StorageDirectory? type in <StorageDirectory?>[
+      null,
+      ...StorageDirectory.values
+    ]) {
       test('getExternalStoragePaths (type: $type) android succeeds', () async {
-        final List<String> result =
+        final List<String>? result =
             await methodChannelPathProvider.getExternalStoragePaths(type: type);
         expect(
           log,
@@ -162,7 +164,7 @@
           ],
         );
 
-        expect(result.length, 1);
+        expect(result!.length, 1);
         expect(result.first, kExternalStoragePaths);
       });
 
@@ -182,7 +184,7 @@
     test('getDownloadsPath macos succeeds', () async {
       methodChannelPathProvider
           .setMockPathProviderPlatform(FakePlatform(operatingSystem: 'macos'));
-      final String result = await methodChannelPathProvider.getDownloadsPath();
+      final String? result = await methodChannelPathProvider.getDownloadsPath();
       expect(
         log,
         <Matcher>[isMethodCall('getDownloadsDirectory', arguments: null)],
diff --git a/packages/plugin_platform_interface/CHANGELOG.md b/packages/plugin_platform_interface/CHANGELOG.md
index 01b5ff7..7df1834 100644
--- a/packages/plugin_platform_interface/CHANGELOG.md
+++ b/packages/plugin_platform_interface/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 1.1.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 1.1.0-nullsafety
+
+* Migrate to null safety.
+
 ## 1.0.3
 
 * Fix homepage in `pubspec.yaml`.
diff --git a/packages/plugin_platform_interface/analysis_options.yaml b/packages/plugin_platform_interface/analysis_options.yaml
new file mode 100644
index 0000000..f4819cd
--- /dev/null
+++ b/packages/plugin_platform_interface/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart
index be48719..cd87b04 100644
--- a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart
+++ b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart
@@ -41,7 +41,7 @@
 /// [MockPlatformInterfaceMixin] for a sample of using Mockito to mock a platform interface.
 abstract class PlatformInterface {
   /// Pass a private, class-specific `const Object()` as the `token`.
-  PlatformInterface({@required Object token}) : _instanceToken = token;
+  PlatformInterface({required Object token}) : _instanceToken = token;
 
   final Object _instanceToken;
 
diff --git a/packages/plugin_platform_interface/pubspec.yaml b/packages/plugin_platform_interface/pubspec.yaml
index ae11b14..05fc918 100644
--- a/packages/plugin_platform_interface/pubspec.yaml
+++ b/packages/plugin_platform_interface/pubspec.yaml
@@ -12,17 +12,17 @@
 # be done when absolutely necessary and after the ecosystem has already migrated to 1.X.Y version
 # that is forward compatible with 2.0.0 (ideally the ecosystem have migrated to depend on:
 # `plugin_platform_interface: >=1.X.Y <3.0.0`).
-version: 1.0.3
+version: 1.1.0-nullsafety.1
 
 repository: https://github.com/flutter/plugins/tree/master/packages/plugin_platform_interface
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
 
 dependencies:
-  meta: ^1.0.0
+  meta: ^1.3.0-nullsafety.3
 
 dev_dependencies:
   mockito: ^4.1.1
-  test: ^1.9.4
-  pedantic: ^1.8.0
+  test: ^1.10.0-nullsafety.1
+  pedantic: ^1.10.0-nullsafety.1
diff --git a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart
index 0488c20..b07dd4d 100644
--- a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart
+++ b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(egarciad): Remove once Mockito is migrated to null safety.
+// @dart = 2.9
 import 'package:mockito/mockito.dart';
 import 'package:test/test.dart';
 
diff --git a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart
index 763d326..80faba4 100755
--- a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart
+++ b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
+// @dart = 2.9
 
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md
index 9c2d8ce..aaf958a 100644
--- a/packages/url_launcher/url_launcher/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 6.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 6.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 5.7.13
 
 * Update Flutter SDK constraint.
diff --git a/packages/url_launcher/url_launcher/analysis_options.yaml b/packages/url_launcher/url_launcher/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/url_launcher/url_launcher/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart
index 4c0f503..80d21b7 100644
--- a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart
+++ b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// TODO(egarciad): Remove once integration_test is migrated to null safety.
+// @dart = 2.9
+
 import 'dart:io' show Platform;
 
 import 'package:flutter/foundation.dart' show kIsWeb;
diff --git a/packages/url_launcher/url_launcher/example/lib/main.dart b/packages/url_launcher/url_launcher/example/lib/main.dart
index f7d90c4..b3e65f3 100644
--- a/packages/url_launcher/url_launcher/example/lib/main.dart
+++ b/packages/url_launcher/url_launcher/example/lib/main.dart
@@ -27,7 +27,7 @@
 }
 
 class MyHomePage extends StatefulWidget {
-  MyHomePage({Key key, this.title}) : super(key: key);
+  MyHomePage({Key? key, required this.title}) : super(key: key);
   final String title;
 
   @override
@@ -35,7 +35,7 @@
 }
 
 class _MyHomePageState extends State<MyHomePage> {
-  Future<void> _launched;
+  Future<void>? _launched;
   String _phone = '';
 
   Future<void> _launchInBrowser(String url) async {
diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml
index 94df1a4..1fdb73c 100644
--- a/packages/url_launcher/url_launcher/example/pubspec.yaml
+++ b/packages/url_launcher/url_launcher/example/pubspec.yaml
@@ -12,9 +12,9 @@
     path: ../../../integration_test
   flutter_driver:
     sdk: flutter
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
   mockito: ^4.1.1
-  plugin_platform_interface: ^1.0.0
+  plugin_platform_interface: ^1.1.0-nullsafety.1
 
 flutter:
   uses-material-design: true
diff --git a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart
index 41b9f6f..eddc126 100644
--- a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart
+++ b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart
@@ -1,3 +1,10 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(egarciad): Remove once mockito is migrated to null safety.
+// @dart = 2.9
+
 import 'package:flutter_test/flutter_test.dart';
 import 'package:flutter/material.dart';
 import 'package:mockito/mockito.dart';
diff --git a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart
index 7a2c213..e56756f 100644
--- a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart
+++ b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// TODO(egarciad): Remove once flutter_driver is migrated to null safety.
+// @dart = 2.9
+
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
diff --git a/packages/url_launcher/url_launcher/lib/src/link.dart b/packages/url_launcher/url_launcher/lib/src/link.dart
index bd54789..f859bc4 100644
--- a/packages/url_launcher/url_launcher/lib/src/link.dart
+++ b/packages/url_launcher/url_launcher/lib/src/link.dart
@@ -40,7 +40,7 @@
   final LinkWidgetBuilder builder;
 
   /// The destination that this link leads to.
-  final Uri uri;
+  final Uri? uri;
 
   /// The target indicating where to open the link.
   final LinkTarget target;
@@ -51,12 +51,11 @@
   /// Creates a widget that renders a real link on the web, and uses WebViews in
   /// native platforms to open links.
   Link({
-    Key key,
-    @required this.uri,
-    LinkTarget target,
-    @required this.builder,
-  })  : target = target ?? LinkTarget.defaultTarget,
-        super(key: key);
+    Key? key,
+    required this.uri,
+    this.target = LinkTarget.defaultTarget,
+    required this.builder,
+  }) : super(key: key);
 
   LinkDelegate get _effectiveDelegate {
     return UrlLauncherPlatform.instance.linkDelegate ??
@@ -90,16 +89,17 @@
   bool get _useWebView {
     if (link.target == LinkTarget.self) return true;
     if (link.target == LinkTarget.blank) return false;
-    return null;
+    return false;
   }
 
   Future<void> _followLink(BuildContext context) async {
-    if (!link.uri.hasScheme) {
+    if (!link.uri!.hasScheme) {
       // A uri that doesn't have a scheme is an internal route name. In this
       // case, we push it via Flutter's navigation system instead of letting the
       // browser handle it.
       final String routeName = link.uri.toString();
-      return pushRouteNameToFramework(context, routeName);
+      await pushRouteNameToFramework(context, routeName);
+      return;
     }
 
     // At this point, we know that the link is external. So we use the `launch`
@@ -119,7 +119,6 @@
         context: ErrorDescription('during launching a link'),
       ));
     }
-    return Future<void>.value(null);
   }
 
   @override
diff --git a/packages/url_launcher/url_launcher/lib/url_launcher.dart b/packages/url_launcher/url_launcher/lib/url_launcher.dart
index 25aa623..6138fff 100644
--- a/packages/url_launcher/url_launcher/lib/url_launcher.dart
+++ b/packages/url_launcher/url_launcher/lib/url_launcher.dart
@@ -62,16 +62,15 @@
 /// is set to true and the universal link failed to launch.
 Future<bool> launch(
   String urlString, {
-  bool forceSafariVC,
-  bool forceWebView,
-  bool enableJavaScript,
-  bool enableDomStorage,
-  bool universalLinksOnly,
-  Map<String, String> headers,
-  Brightness statusBarBrightness,
-  String webOnlyWindowName,
+  bool forceSafariVC = true,
+  bool forceWebView = false,
+  bool enableJavaScript = false,
+  bool enableDomStorage = false,
+  bool universalLinksOnly = false,
+  Map<String, String> headers = const <String, String>{},
+  Brightness? statusBarBrightness,
+  String? webOnlyWindowName,
 }) async {
-  assert(urlString != null);
   final Uri url = Uri.parse(urlString.trimLeft());
   final bool isWebURL = url.scheme == 'http' || url.scheme == 'https';
   if ((forceSafariVC == true || forceWebView == true) && !isWebURL) {
@@ -84,29 +83,32 @@
   /// [true] so that ui is automatically computed if [statusBarBrightness] is set.
   bool previousAutomaticSystemUiAdjustment = true;
   if (statusBarBrightness != null &&
-      defaultTargetPlatform == TargetPlatform.iOS) {
+      defaultTargetPlatform == TargetPlatform.iOS &&
+      WidgetsBinding.instance != null) {
     previousAutomaticSystemUiAdjustment =
-        WidgetsBinding.instance.renderView.automaticSystemUiAdjustment;
-    WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false;
+        WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment;
+    WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment = false;
     SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light
         ? SystemUiOverlayStyle.dark
         : SystemUiOverlayStyle.light);
   }
+
   final bool result = await UrlLauncherPlatform.instance.launch(
     urlString,
-    useSafariVC: forceSafariVC ?? isWebURL,
-    useWebView: forceWebView ?? false,
-    enableJavaScript: enableJavaScript ?? false,
-    enableDomStorage: enableDomStorage ?? false,
-    universalLinksOnly: universalLinksOnly ?? false,
-    headers: headers ?? <String, String>{},
+    useSafariVC: forceSafariVC,
+    useWebView: forceWebView,
+    enableJavaScript: enableJavaScript,
+    enableDomStorage: enableDomStorage,
+    universalLinksOnly: universalLinksOnly,
+    headers: headers,
     webOnlyWindowName: webOnlyWindowName,
   );
-  assert(previousAutomaticSystemUiAdjustment != null);
-  if (statusBarBrightness != null) {
-    WidgetsBinding.instance.renderView.automaticSystemUiAdjustment =
+
+  if (statusBarBrightness != null && WidgetsBinding.instance != null) {
+    WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment =
         previousAutomaticSystemUiAdjustment;
   }
+
   return result;
 }
 
@@ -118,9 +120,6 @@
 /// For more information see the [Managing package visibility](https://developer.android.com/training/basics/intents/package-visibility)
 /// article in the Android docs.
 Future<bool> canLaunch(String urlString) async {
-  if (urlString == null) {
-    return false;
-  }
   return await UrlLauncherPlatform.instance.canLaunch(urlString);
 }
 
diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml
index 8b731fa..e37f267 100644
--- a/packages/url_launcher/url_launcher/pubspec.yaml
+++ b/packages/url_launcher/url_launcher/pubspec.yaml
@@ -2,7 +2,11 @@
 description: Flutter plugin for launching a URL on Android and iOS. Supports
   web, phone, SMS, and email schemes.
 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher
+<<<<<<< HEAD
+version: 6.0.0-nullsafety.1
+=======
 version: 5.7.13
+>>>>>>> master
 
 flutter:
   plugin:
@@ -12,8 +16,9 @@
         pluginClass: UrlLauncherPlugin
       ios:
         pluginClass: FLTURLLauncherPlugin
-      web:
-        default_package: url_launcher_web
+      # TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten).
+      #web:
+      #  default_package: url_launcher_web
       linux:
         default_package: url_laucher_linux
       macos:
@@ -24,25 +29,26 @@
 dependencies:
   flutter:
     sdk: flutter
-  url_launcher_platform_interface: ^1.0.9
+  url_launcher_platform_interface: ^2.0.0-nullsafety
   # The design on https://flutter.dev/go/federated-plugins was to leave
   # this constraint as "any". We cannot do it right now as it fails pub publish
   # validation, so we set a ^ constraint.
   # TODO(amirh): Revisit this (either update this part in the  design or the pub tool).
   # https://github.com/flutter/flutter/issues/46264
-  url_launcher_web: ^0.1.5
-  url_launcher_linux: ^0.0.1
-  url_launcher_macos: ^0.0.1
-  url_launcher_windows: ^0.0.1
+  url_launcher_linux: ^0.1.0-nullsafety
+  url_launcher_macos: ^0.1.0-nullsafety
+  url_launcher_windows: ^0.1.0-nullsafety
+  # TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten).
+  #url_launcher_web: ^0.1.3
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  test: ^1.3.0
+  test: ^1.10.0-nullsafety.1
   mockito: ^4.1.1
-  plugin_platform_interface: ^1.0.0
-  pedantic: ^1.8.0
+  plugin_platform_interface: ^1.1.0-nullsafety.1
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.13+hotfix.5"
diff --git a/packages/url_launcher/url_launcher/test/link_test.dart b/packages/url_launcher/url_launcher/test/link_test.dart
index d525153..46903aa 100644
--- a/packages/url_launcher/url_launcher/test/link_test.dart
+++ b/packages/url_launcher/url_launcher/test/link_test.dart
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
+// TODO(egarciad): Remove once Mockito has been migrated to null safety.
+// @dart = 2.9
 
 import 'dart:ui';
 import 'package:flutter/material.dart';
diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart
index f18e16c..89a7801 100644
--- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart
+++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
+// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety.
+// @dart = 2.9
 
 import 'dart:async';
 import 'dart:ui';
+
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/mockito.dart';
 import 'package:flutter/foundation.dart';
@@ -41,10 +43,6 @@
     });
   });
   group('launch', () {
-    test('requires a non-null urlString', () {
-      expect(() => launch(null), throwsAssertionError);
-    });
-
     test('default behavior', () async {
       await launch('http://flutter.dev/');
       expect(
diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md
index 57da89f..bad287a 100644
--- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.0-nullsafety.1
+
+* Migrate to null safety.
+
 ## 0.0.2+1
 
 * Update Flutter SDK constraint.
diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml
index 65e10e0..e2fb5fc 100644
--- a/packages/url_launcher/url_launcher_linux/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml
@@ -1,6 +1,6 @@
 name: url_launcher_linux
 description: Linux implementation of the url_launcher plugin.
-version: 0.0.2+1
+version: 0.1.0-nullsafety.1
 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux
 
 flutter:
@@ -10,7 +10,7 @@
         pluginClass: UrlLauncherPlugin
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.8"
 
 dependencies:
diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md
index ab13275..8a0e657 100644
--- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md
@@ -1,3 +1,11 @@
+# 0.1.0-nullsafety.1
+
+* Bump SDK to support null safety.
+
+# 0.1.0-nullsafety
+
+* Migrate to null safety.
+
 ## 0.0.2+1
 
 * Update Flutter SDK constraint.
diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml
index 12ce6a0..9ce9c9c 100644
--- a/packages/url_launcher/url_launcher_macos/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml
@@ -3,7 +3,7 @@
 # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump
 # the version to 2.0.0.
 # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
-version: 0.0.2+1
+version: 0.1.0-nullsafety.1
 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos
 
 flutter:
@@ -14,7 +14,7 @@
         fileName: url_launcher_macos.dart
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.8"
 
 dependencies:
diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md
index 26047c7..5bbbe9d 100644
--- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 2.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 1.0.10
 
 * Update Flutter SDK constraint.
diff --git a/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart
index 425dc88..a176972 100644
--- a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart
+++ b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart
@@ -16,7 +16,7 @@
 /// the widget tree under it.
 typedef LinkWidgetBuilder = Widget Function(
   BuildContext context,
-  FollowLink followLink,
+  FollowLink? followLink,
 );
 
 /// Signature for a delegate function to build the [Link] widget.
@@ -31,7 +31,7 @@
 class LinkTarget {
   /// Const private constructor with a [debugLabel] to allow the creation of
   /// multiple distinct const instances.
-  const LinkTarget._({this.debugLabel});
+  const LinkTarget._({required this.debugLabel});
 
   /// Used to distinguish multiple const instances of [LinkTarget].
   final String debugLabel;
@@ -64,7 +64,7 @@
   LinkWidgetBuilder get builder;
 
   /// The destination that this link leads to.
-  Uri get uri;
+  Uri? get uri;
 
   /// The target indicating where to open the link.
   LinkTarget get target;
@@ -80,10 +80,14 @@
   String routeName, {
   @visibleForTesting bool debugForceRouter = false,
 }) {
+  final PlatformMessageCallback? onPlatformMessage = window.onPlatformMessage;
+  if (onPlatformMessage == null) {
+    return Future<ByteData>.value(null);
+  }
   final Completer<ByteData> completer = Completer<ByteData>();
   if (debugForceRouter || _hasRouter(context)) {
     SystemNavigator.routeInformationUpdated(location: routeName);
-    window.onPlatformMessage(
+    onPlatformMessage(
       'flutter/navigation',
       _codec.encodeMethodCall(
         MethodCall('pushRouteInformation', <dynamic, dynamic>{
@@ -94,7 +98,7 @@
       completer.complete,
     );
   } else {
-    window.onPlatformMessage(
+    onPlatformMessage(
       'flutter/navigation',
       _codec.encodeMethodCall(MethodCall('pushRoute', routeName)),
       completer.complete,
diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart
index ac5bfa2..7b9dfc9 100644
--- a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart
+++ b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 
 import 'package:flutter/services.dart';
-import 'package:meta/meta.dart' show required;
 
 import 'link.dart';
 import 'url_launcher_platform_interface.dart';
@@ -15,14 +14,14 @@
 /// An implementation of [UrlLauncherPlatform] that uses method channels.
 class MethodChannelUrlLauncher extends UrlLauncherPlatform {
   @override
-  final LinkDelegate linkDelegate = null;
+  final LinkDelegate? linkDelegate = null;
 
   @override
   Future<bool> canLaunch(String url) {
     return _channel.invokeMethod<bool>(
       'canLaunch',
       <String, Object>{'url': url},
-    );
+    ).then((value) => value ?? false);
   }
 
   @override
@@ -33,13 +32,13 @@
   @override
   Future<bool> launch(
     String url, {
-    @required bool useSafariVC,
-    @required bool useWebView,
-    @required bool enableJavaScript,
-    @required bool enableDomStorage,
-    @required bool universalLinksOnly,
-    @required Map<String, String> headers,
-    String webOnlyWindowName,
+    required bool useSafariVC,
+    required bool useWebView,
+    required bool enableJavaScript,
+    required bool enableDomStorage,
+    required bool universalLinksOnly,
+    required Map<String, String> headers,
+    String? webOnlyWindowName,
   }) {
     return _channel.invokeMethod<bool>(
       'launch',
@@ -52,6 +51,6 @@
         'universalLinksOnly': universalLinksOnly,
         'headers': headers,
       },
-    );
+    ).then((value) => value ?? false);
   }
 }
diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart
index 75002ff..2a4edfa 100644
--- a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart
+++ b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import 'package:meta/meta.dart' show required;
 import 'package:plugin_platform_interface/plugin_platform_interface.dart';
 import 'package:url_launcher_platform_interface/link.dart';
 
@@ -40,7 +39,7 @@
   }
 
   /// The delegate used by the Link widget to build itself.
-  LinkDelegate get linkDelegate;
+  LinkDelegate? get linkDelegate;
 
   /// Returns `true` if this platform is able to launch [url].
   Future<bool> canLaunch(String url) {
@@ -53,13 +52,13 @@
   /// in `package:url_launcher/url_launcher.dart`.
   Future<bool> launch(
     String url, {
-    @required bool useSafariVC,
-    @required bool useWebView,
-    @required bool enableJavaScript,
-    @required bool enableDomStorage,
-    @required bool universalLinksOnly,
-    @required Map<String, String> headers,
-    String webOnlyWindowName,
+    required bool useSafariVC,
+    required bool useWebView,
+    required bool enableJavaScript,
+    required bool enableDomStorage,
+    required bool universalLinksOnly,
+    required Map<String, String> headers,
+    String? webOnlyWindowName,
   }) {
     throw UnimplementedError('launch() has not been implemented.');
   }
diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml
index b8b05b8..e576e96 100644
--- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml
@@ -3,20 +3,19 @@
 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.0.10
+version: 2.0.0-nullsafety.1
 
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.0.5
-  plugin_platform_interface: ^1.0.1
+  plugin_platform_interface: ^1.1.0-nullsafety.1
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
   mockito: ^4.1.1
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.22.0"
diff --git a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart
index 99a885c..58cdd22 100644
--- a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart
+++ b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(egarciad): Remove once Mockito has been migrated to null safety.
+// @dart = 2.9
+
 import 'dart:ui';
 
 import 'package:mockito/mockito.dart';
diff --git a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart
index d88f53a..dfd4b73 100644
--- a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart
+++ b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety.
+// @dart = 2.9
 import 'package:mockito/mockito.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
@@ -42,6 +44,10 @@
     final List<MethodCall> log = <MethodCall>[];
     channel.setMockMethodCallHandler((MethodCall methodCall) async {
       log.add(methodCall);
+
+      // Return null explicitly instead of relying on the implicit null
+      // returned by the method channel if no return statement is specified.
+      return null;
     });
 
     final MethodChannelUrlLauncher launcher = MethodChannelUrlLauncher();
@@ -62,6 +68,12 @@
       );
     });
 
+    test('canLaunch should return false if platform returns null', () async {
+      final canLaunch = await launcher.canLaunch('http://example.com/');
+
+      expect(canLaunch, false);
+    });
+
     test('launch', () async {
       await launcher.launch(
         'http://example.com/',
@@ -270,6 +282,20 @@
       );
     });
 
+    test('launch should return false if platform returns null', () async {
+      final launched = await launcher.launch(
+        'http://example.com/',
+        useSafariVC: true,
+        useWebView: false,
+        enableJavaScript: false,
+        enableDomStorage: false,
+        universalLinksOnly: false,
+        headers: const <String, String>{},
+      );
+
+      expect(launched, false);
+    });
+
     test('closeWebView default behavior', () async {
       await launcher.closeWebView();
       expect(
diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md
index e8db0e4..c8d52f5 100644
--- a/packages/url_launcher/url_launcher_web/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md
@@ -41,7 +41,7 @@
 
 # 0.1.2
 
-- Adds "tel" and "sms" support 
+- Adds "tel" and "sms" support
 
 # 0.1.1+6
 
diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml
index 049c4bb..2d1b8af 100644
--- a/packages/url_launcher/url_launcher_web/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_web/pubspec.yaml
@@ -15,6 +15,12 @@
 
 dependencies:
   url_launcher_platform_interface: ^1.0.9
+  # TODO(mvanbeusekom): Update to use pub.dev once null safety version is published.
+  # url_launcher_platform_interface:
+  #   git:
+  #     url: https://github.com/flutter/plugins.git
+  #     ref: nnbd
+  #     path: packages/url_launcher/url_launcher_platform_interface
   flutter:
     sdk: flutter
   flutter_web_plugins:
@@ -25,6 +31,9 @@
   flutter_test:
     sdk: flutter
   url_launcher: ^5.2.5
+  # TODO(mvanbeusekom): Update to use pub.dev once null safety version is published.
+  # url_launcher:
+  #   path: ../url_launcher
   pedantic: ^1.8.0
   mockito: ^4.1.1
   integration_test:
diff --git a/packages/url_launcher/url_launcher_web/test/pubspec.yaml b/packages/url_launcher/url_launcher_web/test/pubspec.yaml
index e755dff..b8c541f 100644
--- a/packages/url_launcher/url_launcher_web/test/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_web/test/pubspec.yaml
@@ -2,7 +2,7 @@
 publish_to: none
 
 environment:
-  sdk: ">=2.2.2 <3.0.0"
+  sdk: ">=2.10.0-56.0.dev <3.0.0"
 
 dependencies:
   flutter:
diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md
index fb1a83f..e9649ff 100644
--- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 0.1.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 0.1.0-nullsafety
+
+* Migrate to null-safety.
+
 ## 0.0.2+1
 
 * Update Flutter SDK constraint.
diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml
index 8db8d94..d2da4c5 100644
--- a/packages/url_launcher/url_launcher_windows/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml
@@ -3,7 +3,7 @@
 # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump
 # the version to 2.0.0.
 # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
-version: 0.0.2+1
+version: 0.1.0-nullsafety.1
 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows
 
 flutter:
@@ -13,7 +13,7 @@
         pluginClass: UrlLauncherPlugin
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.8"
 
 dependencies:
diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md
index 32614b4..14eaae3 100644
--- a/packages/video_player/video_player/CHANGELOG.md
+++ b/packages/video_player/video_player/CHANGELOG.md
@@ -1,3 +1,19 @@
+## 2.0.0-nullsafety.3
+
+* Dart null safety requires `2.12`.
+
+## 2.0.0-nullsafety.2
+
+* Bump SDK version.
+
+## 2.0.0-nullsafety.1
+
+* Merge master.
+
+## 2.0.0-nullsafety
+
+* Migration to null safety.
+
 ## 1.0.2
 
 * Update Flutter SDK constraint.
diff --git a/packages/video_player/video_player/analysis_options.yaml b/packages/video_player/video_player/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/video_player/video_player/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java
index 78da715..98cf6db 100644
--- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java
+++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v0.1.7), do not edit directly.
+// Autogenerated from Pigeon (v0.1.12), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package io.flutter.plugins.videoplayer;
@@ -597,7 +597,7 @@
   private static HashMap wrapError(Exception exception) {
     HashMap<String, Object> errorMap = new HashMap<>();
     errorMap.put("message", exception.toString());
-    errorMap.put("code", null);
+    errorMap.put("code", exception.getClass().getSimpleName());
     errorMap.put("details", null);
     return errorMap;
   }
diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart
index 639cca9..d2f3836 100644
--- a/packages/video_player/video_player/example/integration_test/video_player_test.dart
+++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart
@@ -11,7 +11,7 @@
 
 void main() {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
-  VideoPlayerController _controller;
+  late VideoPlayerController _controller;
   tearDown(() async => _controller.dispose());
 
   group('asset videos', () {
@@ -22,7 +22,7 @@
     testWidgets('can be initialized', (WidgetTester tester) async {
       await _controller.initialize();
 
-      expect(_controller.value.initialized, true);
+      expect(_controller.value.isInitialized, true);
       expect(_controller.value.position, const Duration(seconds: 0));
       expect(_controller.value.isPlaying, false);
       expect(_controller.value.duration,
diff --git a/packages/video_player/video_player/example/lib/main.dart b/packages/video_player/video_player/example/lib/main.dart
index a99b9da..42eaaa5 100644
--- a/packages/video_player/video_player/example/lib/main.dart
+++ b/packages/video_player/video_player/example/lib/main.dart
@@ -108,7 +108,7 @@
 
 /// A filler card to show the video in a list of scrolling contents.
 class _ExampleCard extends StatelessWidget {
-  const _ExampleCard({Key key, this.title}) : super(key: key);
+  const _ExampleCard({Key? key, required this.title}) : super(key: key);
 
   final String title;
 
@@ -150,7 +150,7 @@
 }
 
 class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> {
-  VideoPlayerController _controller;
+  late VideoPlayerController _controller;
 
   @override
   void initState() {
@@ -206,7 +206,7 @@
 }
 
 class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
-  VideoPlayerController _controller;
+  late VideoPlayerController _controller;
 
   Future<ClosedCaptionFile> _loadCaptions() async {
     final String fileContents = await DefaultAssetBundle.of(context)
@@ -265,7 +265,8 @@
 }
 
 class _ControlsOverlay extends StatelessWidget {
-  const _ControlsOverlay({Key key, this.controller}) : super(key: key);
+  const _ControlsOverlay({Key? key, required this.controller})
+      : super(key: key);
 
   static const _examplePlaybackRates = [
     0.25,
@@ -345,7 +346,7 @@
 }
 
 class _PlayerVideoAndPopPageState extends State<_PlayerVideoAndPopPage> {
-  VideoPlayerController _videoPlayerController;
+  late VideoPlayerController _videoPlayerController;
   bool startedPlaying = false;
 
   @override
diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml
index dd8fd8d..6cfa932 100644
--- a/packages/video_player/video_player/example/pubspec.yaml
+++ b/packages/video_player/video_player/example/pubspec.yaml
@@ -16,7 +16,8 @@
     sdk: flutter
   integration_test:
     path: ../../../integration_test
-  pedantic: ^1.8.0
+  test: any
+  pedantic: ^1.10.0-nullsafety.1
 
 flutter:
   uses-material-design: true
diff --git a/packages/video_player/video_player/example/test_driver/integration_test.dart b/packages/video_player/video_player/example/test_driver/integration_test.dart
index 7a2c213..7873aba 100644
--- a/packages/video_player/video_player/example/test_driver/integration_test.dart
+++ b/packages/video_player/video_player/example/test_driver/integration_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// TODO(egarciad): Remove once Flutter driver is migrated to null safety.
+// @dart = 2.9
+
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
diff --git a/packages/video_player/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart
new file mode 100644
index 0000000..c1ced19
--- /dev/null
+++ b/packages/video_player/video_player/example/test_driver/video_player.dart
@@ -0,0 +1,14 @@
+// Copyright 2019, the Chromium project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(egarciad): Remove once Flutter driver is migrated to null safety.
+// @dart = 2.9
+
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:video_player_example/main.dart' as app;
+
+void main() {
+  enableFlutterDriverExtension();
+  app.main();
+}
diff --git a/packages/video_player/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart
new file mode 100644
index 0000000..fcbdbb2
--- /dev/null
+++ b/packages/video_player/video_player/example/test_driver/video_player_test.dart
@@ -0,0 +1,30 @@
+// Copyright 2019, the Chromium project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(egarciad): Remove once Flutter driver is migrated to null safety.
+// @dart = 2.9
+
+import 'dart:async';
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:test/test.dart';
+
+Future<void> main() async {
+  final FlutterDriver driver = await FlutterDriver.connect();
+  tearDownAll(() async {
+    await driver.close();
+  });
+
+  //TODO(cyanglaz): Use TabBar tabs to navigate between pages after https://github.com/flutter/flutter/issues/16991 is fixed.
+  //TODO(cyanglaz): Un-skip the test after https://github.com/flutter/flutter/issues/43012 is fixed
+  test('Push a page contains video and pop back, do not crash.', () async {
+    final SerializableFinder pushTab = find.byValueKey('push_tab');
+    await driver.waitFor(pushTab);
+    await driver.tap(pushTab);
+    await driver.waitForAbsent(pushTab);
+    await driver.waitFor(find.byValueKey('home_page'));
+    await driver.waitUntilNoTransientCallbacks();
+    final Health health = await driver.checkHealth();
+    expect(health.status, HealthStatus.ok);
+  }, skip: 'Cirrus CI currently hangs while playing videos');
+}
diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h
index 3c68b3d..84e8fc5 100644
--- a/packages/video_player/video_player/ios/Classes/messages.h
+++ b/packages/video_player/video_player/ios/Classes/messages.h
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v0.1.7), do not edit directly.
+// Autogenerated from Pigeon (v0.1.12), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 #import <Foundation/Foundation.h>
 @protocol FlutterBinaryMessenger;
diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m
index e71f8b8..58ff729 100644
--- a/packages/video_player/video_player/ios/Classes/messages.m
+++ b/packages/video_player/video_player/ios/Classes/messages.m
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v0.1.7), do not edit directly.
+// Autogenerated from Pigeon (v0.1.12), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 #import "messages.h"
 #import <Flutter/Flutter.h>
@@ -7,6 +7,7 @@
 #error File requires ARC to be enabled.
 #endif
 
+#ifndef __clang_analyzer__
 static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
   NSDictionary *errorDict = (NSDictionary *)[NSNull null];
   if (error) {
@@ -59,9 +60,9 @@
   return result;
 }
 - (NSDictionary *)toMap {
-  return [NSDictionary
-      dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
-                                   @"textureId", nil];
+  return
+      [NSDictionary dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]),
+                                                 @"textureId", nil];
 }
 @end
 
@@ -112,10 +113,9 @@
 }
 - (NSDictionary *)toMap {
   return [NSDictionary
-      dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
-                                   @"textureId",
-                                   (self.isLooping != nil ? self.isLooping : [NSNull null]),
-                                   @"isLooping", nil];
+      dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
+                                   (self.isLooping ? self.isLooping : [NSNull null]), @"isLooping",
+                                   nil];
 }
 @end
 
@@ -134,9 +134,8 @@
 }
 - (NSDictionary *)toMap {
   return [NSDictionary
-      dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
-                                   @"textureId", (self.volume != nil ? self.volume : [NSNull null]),
-                                   @"volume", nil];
+      dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
+                                   (self.volume ? self.volume : [NSNull null]), @"volume", nil];
 }
 @end
 
@@ -155,9 +154,8 @@
 }
 - (NSDictionary *)toMap {
   return [NSDictionary
-      dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
-                                   @"textureId", (self.speed != nil ? self.speed : [NSNull null]),
-                                   @"speed", nil];
+      dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
+                                   (self.speed ? self.speed : [NSNull null]), @"speed", nil];
 }
 @end
 
@@ -176,10 +174,9 @@
 }
 - (NSDictionary *)toMap {
   return [NSDictionary
-      dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
-                                   @"textureId",
-                                   (self.position != nil ? self.position : [NSNull null]),
-                                   @"position", nil];
+      dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
+                                   (self.position ? self.position : [NSNull null]), @"position",
+                                   nil];
 }
 @end
 
@@ -194,7 +191,7 @@
 }
 - (NSDictionary *)toMap {
   return [NSDictionary
-      dictionaryWithObjectsAndKeys:(self.mixWithOthers != nil ? self.mixWithOthers : [NSNull null]),
+      dictionaryWithObjectsAndKeys:(self.mixWithOthers ? self.mixWithOthers : [NSNull null]),
                                    @"mixWithOthers", nil];
 }
 @end
@@ -365,3 +362,4 @@
     }
   }
 }
+#endif
diff --git a/packages/video_player/video_player/lib/src/closed_caption_file.dart b/packages/video_player/video_player/lib/src/closed_caption_file.dart
index 550e30a..eae9bf5 100644
--- a/packages/video_player/video_player/lib/src/closed_caption_file.dart
+++ b/packages/video_player/video_player/lib/src/closed_caption_file.dart
@@ -31,7 +31,11 @@
   ///
   /// This is not recommended for direct use unless you are writing a parser for
   /// a new closed captioning file type.
-  const Caption({this.number, this.start, this.end, this.text});
+  const Caption(
+      {required this.number,
+      required this.start,
+      required this.end,
+      required this.text});
 
   /// The number that this caption was assigned.
   final int number;
@@ -46,6 +50,11 @@
   /// and [end].
   final String text;
 
+  /// A no caption object. This is a caption with [start] and [end] durations of zero,
+  /// and an empty [text] string.
+  static const Caption none =
+      Caption(number: 0, start: Duration.zero, end: Duration.zero, text: '');
+
   @override
   String toString() {
     return '$runtimeType('
diff --git a/packages/video_player/video_player/lib/src/sub_rip.dart b/packages/video_player/video_player/lib/src/sub_rip.dart
index 15dc43c..11456db 100644
--- a/packages/video_player/video_player/lib/src/sub_rip.dart
+++ b/packages/video_player/video_player/lib/src/sub_rip.dart
@@ -41,8 +41,7 @@
       end: startAndEnd.end,
       text: text,
     );
-
-    if (newCaption.start != null && newCaption.end != null) {
+    if (newCaption.start != newCaption.end) {
       captions.add(newCaption);
     }
   }
@@ -64,7 +63,7 @@
         RegExp(_subRipTimeStamp + _subRipArrow + _subRipTimeStamp);
 
     if (!format.hasMatch(line)) {
-      return _StartAndEnd(null, null);
+      return _StartAndEnd(Duration.zero, Duration.zero);
     }
 
     final List<String> times = line.split(_subRipArrow);
@@ -84,7 +83,7 @@
 // Duration(hours: 0, minutes: 1, seconds: 59, milliseconds: 084)
 Duration _parseSubRipTimestamp(String timestampString) {
   if (!RegExp(_subRipTimeStamp).hasMatch(timestampString)) {
-    return null;
+    return Duration.zero;
   }
 
   final List<String> commaSections = timestampString.split(',');
diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart
index ac16450..6a2af76 100644
--- a/packages/video_player/video_player/lib/video_player.dart
+++ b/packages/video_player/video_player/lib/video_player.dart
@@ -28,11 +28,12 @@
   /// Constructs a video with the given values. Only [duration] is required. The
   /// rest will initialize with default values when unset.
   VideoPlayerValue({
-    @required this.duration,
-    this.size,
-    this.position = const Duration(),
-    this.caption = const Caption(),
+    required this.duration,
+    this.size = Size.zero,
+    this.position = Duration.zero,
+    this.caption = Caption.none,
     this.buffered = const <DurationRange>[],
+    this.isInitialized = false,
     this.isPlaying = false,
     this.isLooping = false,
     this.isBuffering = false,
@@ -41,17 +42,20 @@
     this.errorDescription,
   });
 
-  /// Returns an instance with a `null` [Duration].
-  VideoPlayerValue.uninitialized() : this(duration: null);
+  /// Returns an instance for a video that hasn't been loaded.
+  VideoPlayerValue.uninitialized()
+      : this(duration: Duration.zero, isInitialized: false);
 
-  /// Returns an instance with a `null` [Duration] and the given
-  /// [errorDescription].
+  /// Returns an instance with the given [errorDescription].
   VideoPlayerValue.erroneous(String errorDescription)
-      : this(duration: null, errorDescription: errorDescription);
+      : this(
+            duration: Duration.zero,
+            isInitialized: false,
+            errorDescription: errorDescription);
 
   /// The total duration of the video.
   ///
-  /// Is null when [initialized] is false.
+  /// The duration is [Duration.zero] if the video hasn't been initialized.
   final Duration duration;
 
   /// The current playback position.
@@ -60,7 +64,7 @@
   /// The [Caption] that should be displayed based on the current [position].
   ///
   /// This field will never be null. If there is no caption for the current
-  /// [position], this will be an empty [Caption] object.
+  /// [position], this will be a [Caption.none] object.
   final Caption caption;
 
   /// The currently buffered ranges.
@@ -84,7 +88,7 @@
   /// A description of the error if present.
   ///
   /// If [hasError] is false this is [null].
-  final String errorDescription;
+  final String? errorDescription;
 
   /// The [size] of the currently loaded video.
   ///
@@ -92,7 +96,7 @@
   final Size size;
 
   /// Indicates whether or not the video has been loaded and is ready to play.
-  bool get initialized => duration != null;
+  final bool isInitialized;
 
   /// Indicates whether or not the video is in an error state. If this is true
   /// [errorDescription] should have information about the problem.
@@ -101,7 +105,7 @@
   /// Returns [size.width] / [size.height] when size is non-null, or `1.0.` when
   /// size is null or the aspect ratio would be less than or equal to 0.0.
   double get aspectRatio {
-    if (size == null || size.width == 0 || size.height == 0) {
+    if (!isInitialized || size.width == 0 || size.height == 0) {
       return 1.0;
     }
     final double aspectRatio = size.width / size.height;
@@ -114,17 +118,18 @@
   /// Returns a new instance that has the same values as this current instance,
   /// except for any overrides passed in as arguments to [copyWidth].
   VideoPlayerValue copyWith({
-    Duration duration,
-    Size size,
-    Duration position,
-    Caption caption,
-    List<DurationRange> buffered,
-    bool isPlaying,
-    bool isLooping,
-    bool isBuffering,
-    double volume,
-    double playbackSpeed,
-    String errorDescription,
+    Duration? duration,
+    Size? size,
+    Duration? position,
+    Caption? caption,
+    List<DurationRange>? buffered,
+    bool? isInitialized,
+    bool? isPlaying,
+    bool? isLooping,
+    bool? isBuffering,
+    double? volume,
+    double? playbackSpeed,
+    String? errorDescription,
   }) {
     return VideoPlayerValue(
       duration: duration ?? this.duration,
@@ -132,6 +137,7 @@
       position: position ?? this.position,
       caption: caption ?? this.caption,
       buffered: buffered ?? this.buffered,
+      isInitialized: isInitialized ?? this.isInitialized,
       isPlaying: isPlaying ?? this.isPlaying,
       isLooping: isLooping ?? this.isLooping,
       isBuffering: isBuffering ?? this.isBuffering,
@@ -149,6 +155,7 @@
         'position: $position, '
         'caption: $caption, '
         'buffered: [${buffered.join(', ')}], '
+        'isInitialized: $isInitialized, '
         'isPlaying: $isPlaying, '
         'isLooping: $isLooping, '
         'isBuffering: $isBuffering, '
@@ -178,7 +185,7 @@
       {this.package, this.closedCaptionFile, this.videoPlayerOptions})
       : dataSourceType = DataSourceType.asset,
         formatHint = null,
-        super(VideoPlayerValue(duration: null));
+        super(VideoPlayerValue(duration: Duration.zero));
 
   /// Constructs a [VideoPlayerController] playing a video from obtained from
   /// the network.
@@ -191,7 +198,7 @@
       {this.formatHint, this.closedCaptionFile, this.videoPlayerOptions})
       : dataSourceType = DataSourceType.network,
         package = null,
-        super(VideoPlayerValue(duration: null));
+        super(VideoPlayerValue(duration: Duration.zero));
 
   /// Constructs a [VideoPlayerController] playing a video from a file.
   ///
@@ -203,9 +210,7 @@
         dataSourceType = DataSourceType.file,
         package = null,
         formatHint = null,
-        super(VideoPlayerValue(duration: null));
-
-  int _textureId;
+        super(VideoPlayerValue(duration: Duration.zero));
 
   /// The URI to the video file. This will be in different formats depending on
   /// the [DataSourceType] of the original video.
@@ -213,31 +218,36 @@
 
   /// **Android only**. Will override the platform's generic file format
   /// detection with whatever is set here.
-  final VideoFormat formatHint;
+  final VideoFormat? formatHint;
 
   /// Describes the type of data source this [VideoPlayerController]
   /// is constructed with.
   final DataSourceType dataSourceType;
 
   /// Provide additional configuration options (optional). Like setting the audio mode to mix
-  final VideoPlayerOptions videoPlayerOptions;
+  final VideoPlayerOptions? videoPlayerOptions;
 
   /// Only set for [asset] videos. The package that the asset was loaded from.
-  final String package;
+  final String? package;
 
   /// Optional field to specify a file containing the closed
   /// captioning.
   ///
   /// This future will be awaited and the file will be loaded when
   /// [initialize()] is called.
-  final Future<ClosedCaptionFile> closedCaptionFile;
+  final Future<ClosedCaptionFile>? closedCaptionFile;
 
-  ClosedCaptionFile _closedCaptionFile;
-  Timer _timer;
+  ClosedCaptionFile? _closedCaptionFile;
+  Timer? _timer;
   bool _isDisposed = false;
-  Completer<void> _creatingCompleter;
-  StreamSubscription<dynamic> _eventSubscription;
-  _VideoAppLifeCycleObserver _lifeCycleObserver;
+  Completer<void>? _creatingCompleter;
+  StreamSubscription<dynamic>? _eventSubscription;
+  late _VideoAppLifeCycleObserver _lifeCycleObserver;
+
+  /// The id of a texture that hasn't been initialized.
+  @visibleForTesting
+  static const int kUninitializedTextureId = -1;
+  int _textureId = kUninitializedTextureId;
 
   /// This is just exposed for testing. It shouldn't be used by anyone depending
   /// on the plugin.
@@ -250,7 +260,7 @@
     _lifeCycleObserver.initialize();
     _creatingCompleter = Completer<void>();
 
-    DataSource dataSourceDescription;
+    late DataSource dataSourceDescription;
     switch (dataSourceType) {
       case DataSourceType.asset:
         dataSourceDescription = DataSource(
@@ -276,11 +286,12 @@
 
     if (videoPlayerOptions?.mixWithOthers != null) {
       await _videoPlayerPlatform
-          .setMixWithOthers(videoPlayerOptions.mixWithOthers);
+          .setMixWithOthers(videoPlayerOptions!.mixWithOthers);
     }
 
-    _textureId = await _videoPlayerPlatform.create(dataSourceDescription);
-    _creatingCompleter.complete(null);
+    _textureId = (await _videoPlayerPlatform.create(dataSourceDescription)) ??
+        kUninitializedTextureId;
+    _creatingCompleter!.complete(null);
     final Completer<void> initializingCompleter = Completer<void>();
 
     void eventListener(VideoEvent event) {
@@ -293,6 +304,7 @@
           value = value.copyWith(
             duration: event.duration,
             size: event.size,
+            isInitialized: event.duration != null,
           );
           initializingCompleter.complete(null);
           _applyLooping();
@@ -325,8 +337,8 @@
     }
 
     void errorListener(Object obj) {
-      final PlatformException e = obj;
-      value = VideoPlayerValue.erroneous(e.message);
+      final PlatformException e = obj as PlatformException;
+      value = VideoPlayerValue.erroneous(e.message!);
       _timer?.cancel();
       if (!initializingCompleter.isCompleted) {
         initializingCompleter.completeError(obj);
@@ -342,7 +354,7 @@
   @override
   Future<void> dispose() async {
     if (_creatingCompleter != null) {
-      await _creatingCompleter.future;
+      await _creatingCompleter!.future;
       if (!_isDisposed) {
         _isDisposed = true;
         _timer?.cancel();
@@ -379,14 +391,14 @@
   }
 
   Future<void> _applyLooping() async {
-    if (!value.initialized || _isDisposed) {
+    if (!value.isInitialized || _isDisposed) {
       return;
     }
     await _videoPlayerPlatform.setLooping(_textureId, value.isLooping);
   }
 
   Future<void> _applyPlayPause() async {
-    if (!value.initialized || _isDisposed) {
+    if (!value.isInitialized || _isDisposed) {
       return;
     }
     if (value.isPlaying) {
@@ -400,8 +412,8 @@
           if (_isDisposed) {
             return;
           }
-          final Duration newPosition = await position;
-          if (_isDisposed) {
+          final Duration? newPosition = await position;
+          if (newPosition == null) {
             return;
           }
           _updatePosition(newPosition);
@@ -419,14 +431,14 @@
   }
 
   Future<void> _applyVolume() async {
-    if (!value.initialized || _isDisposed) {
+    if (!value.isInitialized || _isDisposed) {
       return;
     }
     await _videoPlayerPlatform.setVolume(_textureId, value.volume);
   }
 
   Future<void> _applyPlaybackSpeed() async {
-    if (!value.initialized || _isDisposed) {
+    if (!value.isInitialized || _isDisposed) {
       return;
     }
 
@@ -442,7 +454,7 @@
   }
 
   /// The position in the current video.
-  Future<Duration> get position async {
+  Future<Duration?> get position async {
     if (_isDisposed) {
       return null;
     }
@@ -519,17 +531,17 @@
   /// [Caption].
   Caption _getCaptionAt(Duration position) {
     if (_closedCaptionFile == null) {
-      return Caption();
+      return Caption.none;
     }
 
     // TODO: This would be more efficient as a binary search.
-    for (final caption in _closedCaptionFile.captions) {
+    for (final caption in _closedCaptionFile!.captions) {
       if (caption.start <= position && caption.end >= position) {
         return caption;
       }
     }
 
-    return Caption();
+    return Caption.none;
   }
 
   void _updatePosition(Duration position) {
@@ -545,7 +557,7 @@
   final VideoPlayerController _controller;
 
   void initialize() {
-    WidgetsBinding.instance.addObserver(this);
+    WidgetsBinding.instance!.addObserver(this);
   }
 
   @override
@@ -565,7 +577,7 @@
   }
 
   void dispose() {
-    WidgetsBinding.instance.removeObserver(this);
+    WidgetsBinding.instance!.removeObserver(this);
   }
 }
 
@@ -594,8 +606,9 @@
     };
   }
 
-  VoidCallback _listener;
-  int _textureId;
+  late VoidCallback _listener;
+
+  late int _textureId;
 
   @override
   void initState() {
@@ -622,7 +635,7 @@
 
   @override
   Widget build(BuildContext context) {
-    return _textureId == null
+    return _textureId == VideoPlayerController.kUninitializedTextureId
         ? Container()
         : _videoPlayerPlatform.buildView(_textureId);
   }
@@ -646,7 +659,7 @@
   /// [backgroundColor] defaults to gray at 50% opacity. This is the background
   /// color behind both [playedColor] and [bufferedColor] to denote the total
   /// size of the video compared to either of those values.
-  VideoProgressColors({
+  const VideoProgressColors({
     this.playedColor = const Color.fromRGBO(255, 0, 0, 0.7),
     this.bufferedColor = const Color.fromRGBO(50, 50, 200, 0.2),
     this.backgroundColor = const Color.fromRGBO(200, 200, 200, 0.5),
@@ -670,8 +683,8 @@
 
 class _VideoScrubber extends StatefulWidget {
   _VideoScrubber({
-    @required this.child,
-    @required this.controller,
+    required this.child,
+    required this.controller,
   });
 
   final Widget child;
@@ -689,7 +702,7 @@
   @override
   Widget build(BuildContext context) {
     void seekToRelativePosition(Offset globalPosition) {
-      final RenderBox box = context.findRenderObject();
+      final RenderBox box = context.findRenderObject() as RenderBox;
       final Offset tapPos = box.globalToLocal(globalPosition);
       final double relative = tapPos.dx / box.size.width;
       final Duration position = controller.value.duration * relative;
@@ -700,7 +713,7 @@
       behavior: HitTestBehavior.opaque,
       child: widget.child,
       onHorizontalDragStart: (DragStartDetails details) {
-        if (!controller.value.initialized) {
+        if (!controller.value.isInitialized) {
           return;
         }
         _controllerWasPlaying = controller.value.isPlaying;
@@ -709,7 +722,7 @@
         }
       },
       onHorizontalDragUpdate: (DragUpdateDetails details) {
-        if (!controller.value.initialized) {
+        if (!controller.value.isInitialized) {
           return;
         }
         seekToRelativePosition(details.globalPosition);
@@ -720,7 +733,7 @@
         }
       },
       onTapDown: (TapDownDetails details) {
-        if (!controller.value.initialized) {
+        if (!controller.value.isInitialized) {
           return;
         }
         seekToRelativePosition(details.globalPosition);
@@ -745,10 +758,10 @@
   /// to `top: 5.0`.
   VideoProgressIndicator(
     this.controller, {
-    VideoProgressColors colors,
-    this.allowScrubbing,
+    this.colors = const VideoProgressColors(),
+    required this.allowScrubbing,
     this.padding = const EdgeInsets.only(top: 5.0),
-  }) : colors = colors ?? VideoProgressColors();
+  });
 
   /// The [VideoPlayerController] that actually associates a video with this
   /// widget.
@@ -785,7 +798,7 @@
     };
   }
 
-  VoidCallback listener;
+  late VoidCallback listener;
 
   VideoPlayerController get controller => widget.controller;
 
@@ -806,7 +819,7 @@
   @override
   Widget build(BuildContext context) {
     Widget progressIndicator;
-    if (controller.value.initialized) {
+    if (controller.value.isInitialized) {
       final int duration = controller.value.duration.inMilliseconds;
       final int position = controller.value.position.inMilliseconds;
 
@@ -878,17 +891,17 @@
   /// [VideoPlayerValue.caption].
   ///
   /// If [text] is null, nothing will be displayed.
-  const ClosedCaption({Key key, this.text, this.textStyle}) : super(key: key);
+  const ClosedCaption({Key? key, this.text, this.textStyle}) : super(key: key);
 
   /// The text that will be shown in the closed caption, or null if no caption
   /// should be shown.
-  final String text;
+  final String? text;
 
   /// Specifies how the text in the closed caption should look.
   ///
   /// If null, defaults to [DefaultTextStyle.of(context).style] with size 36
   /// font colored white.
-  final TextStyle textStyle;
+  final TextStyle? textStyle;
 
   @override
   Widget build(BuildContext context) {
@@ -913,7 +926,7 @@
           ),
           child: Padding(
             padding: EdgeInsets.symmetric(horizontal: 2.0),
-            child: Text(text, style: effectiveTextStyle),
+            child: Text(text!, style: effectiveTextStyle),
           ),
         ),
       ),
diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart
index 427aea2..f1771af 100644
--- a/packages/video_player/video_player/pigeons/messages.dart
+++ b/packages/video_player/video_player/pigeons/messages.dart
@@ -1,3 +1,5 @@
+// @dart = 2.9
+
 import 'package:pigeon/pigeon_lib.dart';
 
 class TextureMessage {
diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml
index fa55ba4..3e86c1d 100644
--- a/packages/video_player/video_player/pubspec.yaml
+++ b/packages/video_player/video_player/pubspec.yaml
@@ -1,7 +1,14 @@
 name: video_player
 description: Flutter plugin for displaying inline video with other Flutter
   widgets on Android, iOS, and web.
+<<<<<<< HEAD
+# 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump
+# the version to 2.0.0.
+# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
+version: 2.0.0-nullsafety.3
+=======
 version: 1.0.2
+>>>>>>> master
 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player
 
 flutter:
@@ -16,15 +23,15 @@
         default_package: video_player_web
 
 dependencies:
-  meta: ^1.0.5
-  video_player_platform_interface: ^2.2.0
+  meta: ^1.3.0-nullsafety.3
+  video_player_platform_interface: ^3.0.0-nullsafety.2
 
   # The design on https://flutter.dev/go/federated-plugins was to leave
   # this constraint as "any". We cannot do it right now as it fails pub publish
   # validation, so we set a ^ constraint.
   # TODO(amirh): Revisit this (either update this part in the  design or the pub tool).
   # https://github.com/flutter/flutter/issues/46264
-  video_player_web: ">=0.1.4 <2.0.0"
+  video_player_web: ^2.0.0-nullsafety.1
 
   flutter:
     sdk: flutter
@@ -32,9 +39,9 @@
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
   pigeon: 0.1.7
 
 environment:
-  sdk: ">=2.8.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.13+hotfix.5"
diff --git a/packages/video_player/video_player/test/sub_rip_file_test.dart b/packages/video_player/video_player/test/sub_rip_file_test.dart
index cf25ff7..2b9803d 100644
--- a/packages/video_player/video_player/test/sub_rip_file_test.dart
+++ b/packages/video_player/video_player/test/sub_rip_file_test.dart
@@ -108,6 +108,6 @@
 
 3
 00:01:54,724 --> 00:01:6,760
-This one should be ignored because the 
+This one should be ignored because the
 ned time is missing a digit.
 ''';
diff --git a/packages/video_player/video_player/test/video_player_initialization_test.dart b/packages/video_player/video_player/test/video_player_initialization_test.dart
index 231c399..1a09ed9 100644
--- a/packages/video_player/video_player/test/video_player_initialization_test.dart
+++ b/packages/video_player/video_player/test/video_player_initialization_test.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
-
 import 'package:flutter/widgets.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:video_player/video_player.dart';
diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart
index a7b23c3..3e9800f 100644
--- a/packages/video_player/video_player/test/video_player_test.dart
+++ b/packages/video_player/video_player/test/video_player_test.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
-
 import 'dart:async';
 import 'dart:io';
 
@@ -18,7 +16,7 @@
 
 class FakeController extends ValueNotifier<VideoPlayerValue>
     implements VideoPlayerController {
-  FakeController() : super(VideoPlayerValue(duration: null));
+  FakeController() : super(VideoPlayerValue(duration: Duration.zero));
 
   @override
   Future<void> dispose() async {
@@ -26,7 +24,7 @@
   }
 
   @override
-  int textureId;
+  int textureId = VideoPlayerController.kUninitializedTextureId;
 
   @override
   String get dataSource => '';
@@ -35,7 +33,7 @@
   DataSourceType get dataSourceType => DataSourceType.file;
 
   @override
-  String get package => null;
+  String get package => '';
 
   @override
   Future<Duration> get position async => value.position;
@@ -62,13 +60,13 @@
   Future<void> setLooping(bool looping) async {}
 
   @override
-  VideoFormat get formatHint => null;
+  VideoFormat? get formatHint => null;
 
   @override
   Future<ClosedCaptionFile> get closedCaptionFile => _loadClosedCaption();
 
   @override
-  VideoPlayerOptions get videoPlayerOptions => null;
+  VideoPlayerOptions? get videoPlayerOptions => null;
 }
 
 Future<ClosedCaptionFile> _loadClosedCaption() async =>
@@ -80,11 +78,13 @@
     return <Caption>[
       Caption(
         text: 'one',
+        number: 0,
         start: Duration(milliseconds: 100),
         end: Duration(milliseconds: 200),
       ),
       Caption(
         text: 'two',
+        number: 1,
         start: Duration(milliseconds: 300),
         end: Duration(milliseconds: 400),
       ),
@@ -101,6 +101,7 @@
     controller.textureId = 123;
     controller.value = controller.value.copyWith(
       duration: const Duration(milliseconds: 100),
+      isInitialized: true,
     );
 
     await tester.pump();
@@ -133,8 +134,8 @@
       await tester.pumpWidget(MaterialApp(home: ClosedCaption(text: text)));
 
       final Text textWidget = tester.widget<Text>(find.text(text));
-      expect(textWidget.style.fontSize, 36.0);
-      expect(textWidget.style.color, Colors.white);
+      expect(textWidget.style!.fontSize, 36.0);
+      expect(textWidget.style!.color, Colors.white);
     });
 
     testWidgets('uses given text and style', (WidgetTester tester) async {
@@ -149,7 +150,7 @@
       expect(find.text(text), findsOneWidget);
 
       final Text textWidget = tester.widget<Text>(find.text(text));
-      expect(textWidget.style.fontSize, textStyle.fontSize);
+      expect(textWidget.style!.fontSize, textStyle.fontSize);
     });
 
     testWidgets('handles null text', (WidgetTester tester) async {
@@ -173,7 +174,7 @@
   });
 
   group('VideoPlayerController', () {
-    FakeVideoPlayerPlatform fakeVideoPlayerPlatform;
+    late FakeVideoPlayerPlatform fakeVideoPlayerPlatform;
 
     setUp(() {
       fakeVideoPlayerPlatform = FakeVideoPlayerPlatform();
@@ -221,7 +222,7 @@
           'http://testing.com/invalid_url',
         );
         try {
-          dynamic error;
+          late dynamic error;
           fakeVideoPlayerPlatform.forceInitError = true;
           await controller.initialize().catchError((dynamic e) => error = e);
           final PlatformException platformEx = error;
@@ -245,13 +246,14 @@
       final VideoPlayerController controller = VideoPlayerController.network(
         'https://127.0.0.1',
       );
-      expect(controller.textureId, isNull);
+      expect(
+          controller.textureId, VideoPlayerController.kUninitializedTextureId);
       expect(await controller.position, const Duration(seconds: 0));
       await controller.initialize();
 
       await controller.dispose();
 
-      expect(controller.textureId, isNotNull);
+      expect(controller.textureId, 0);
       expect(await controller.position, isNull);
     });
 
@@ -390,19 +392,19 @@
 
         await controller.initialize();
         expect(controller.value.position, const Duration());
-        expect(controller.value.caption.text, isNull);
+        expect(controller.value.caption.text, '');
 
         await controller.seekTo(const Duration(milliseconds: 100));
         expect(controller.value.caption.text, 'one');
 
         await controller.seekTo(const Duration(milliseconds: 250));
-        expect(controller.value.caption.text, isNull);
+        expect(controller.value.caption.text, '');
 
         await controller.seekTo(const Duration(milliseconds: 300));
         expect(controller.value.caption.text, 'two');
 
         await controller.seekTo(const Duration(milliseconds: 500));
-        expect(controller.value.caption.text, isNull);
+        expect(controller.value.caption.text, '');
 
         await controller.seekTo(const Duration(milliseconds: 300));
         expect(controller.value.caption.text, 'two');
@@ -419,8 +421,7 @@
         await controller.play();
         expect(controller.value.isPlaying, isTrue);
         final FakeVideoEventStream fakeVideoEventStream =
-            fakeVideoPlayerPlatform.streams[controller.textureId];
-        assert(fakeVideoEventStream != null);
+            fakeVideoPlayerPlatform.streams[controller.textureId]!;
 
         fakeVideoEventStream.eventsChannel
             .sendEvent(<String, dynamic>{'event': 'completed'});
@@ -438,8 +439,7 @@
         expect(controller.value.isBuffering, false);
         expect(controller.value.buffered, isEmpty);
         final FakeVideoEventStream fakeVideoEventStream =
-            fakeVideoPlayerPlatform.streams[controller.textureId];
-        assert(fakeVideoEventStream != null);
+            fakeVideoPlayerPlatform.streams[controller.textureId]!;
 
         fakeVideoEventStream.eventsChannel
             .sendEvent(<String, dynamic>{'event': 'bufferingStart'});
@@ -496,9 +496,9 @@
     test('uninitialized()', () {
       final VideoPlayerValue uninitialized = VideoPlayerValue.uninitialized();
 
-      expect(uninitialized.duration, isNull);
-      expect(uninitialized.position, equals(const Duration(seconds: 0)));
-      expect(uninitialized.caption, equals(const Caption()));
+      expect(uninitialized.duration, equals(Duration.zero));
+      expect(uninitialized.position, equals(Duration.zero));
+      expect(uninitialized.caption, equals(Caption.none));
       expect(uninitialized.buffered, isEmpty);
       expect(uninitialized.isPlaying, isFalse);
       expect(uninitialized.isLooping, isFalse);
@@ -506,9 +506,8 @@
       expect(uninitialized.volume, 1.0);
       expect(uninitialized.playbackSpeed, 1.0);
       expect(uninitialized.errorDescription, isNull);
-      expect(uninitialized.size, isNull);
-      expect(uninitialized.size, isNull);
-      expect(uninitialized.initialized, isFalse);
+      expect(uninitialized.size, equals(Size.zero));
+      expect(uninitialized.isInitialized, isFalse);
       expect(uninitialized.hasError, isFalse);
       expect(uninitialized.aspectRatio, 1.0);
     });
@@ -517,9 +516,9 @@
       const String errorMessage = 'foo';
       final VideoPlayerValue error = VideoPlayerValue.erroneous(errorMessage);
 
-      expect(error.duration, isNull);
-      expect(error.position, equals(const Duration(seconds: 0)));
-      expect(error.caption, equals(const Caption()));
+      expect(error.duration, equals(Duration.zero));
+      expect(error.position, equals(Duration.zero));
+      expect(error.caption, equals(Caption.none));
       expect(error.buffered, isEmpty);
       expect(error.isPlaying, isFalse);
       expect(error.isLooping, isFalse);
@@ -527,9 +526,8 @@
       expect(error.volume, 1.0);
       expect(error.playbackSpeed, 1.0);
       expect(error.errorDescription, errorMessage);
-      expect(error.size, isNull);
-      expect(error.size, isNull);
-      expect(error.initialized, isFalse);
+      expect(error.size, equals(Size.zero));
+      expect(error.isInitialized, isFalse);
       expect(error.hasError, isTrue);
       expect(error.aspectRatio, 1.0);
     });
@@ -538,10 +536,12 @@
       const Duration duration = Duration(seconds: 5);
       const Size size = Size(400, 300);
       const Duration position = Duration(seconds: 1);
-      const Caption caption = Caption(text: 'foo');
+      const Caption caption = Caption(
+          text: 'foo', number: 0, start: Duration.zero, end: Duration.zero);
       final List<DurationRange> buffered = <DurationRange>[
         DurationRange(const Duration(seconds: 0), const Duration(seconds: 4))
       ];
+      const bool isInitialized = true;
       const bool isPlaying = true;
       const bool isLooping = true;
       const bool isBuffering = true;
@@ -554,6 +554,7 @@
         position: position,
         caption: caption,
         buffered: buffered,
+        isInitialized: isInitialized,
         isPlaying: isPlaying,
         isLooping: isLooping,
         isBuffering: isBuffering,
@@ -568,6 +569,7 @@
           'position: 0:00:01.000000, '
           'caption: Caption(number: null, start: null, end: null, text: foo), '
           'buffered: [DurationRange(start: 0:00:00.000000, end: 0:00:04.000000)], '
+          'isInitialized: true, '
           'isPlaying: true, '
           'isLooping: true, '
           'isBuffering: true, '
@@ -586,15 +588,16 @@
     group('aspectRatio', () {
       test('640x480 -> 4:3', () {
         final value = VideoPlayerValue(
+          isInitialized: true,
           size: Size(640, 480),
           duration: Duration(seconds: 1),
         );
         expect(value.aspectRatio, 4 / 3);
       });
 
-      test('null size -> 1.0', () {
+      test('no size -> 1.0', () {
         final value = VideoPlayerValue(
-          size: null,
+          isInitialized: true,
           duration: Duration(seconds: 1),
         );
         expect(value.aspectRatio, 1.0);
@@ -602,6 +605,7 @@
 
       test('height = 0 -> 1.0', () {
         final value = VideoPlayerValue(
+          isInitialized: true,
           size: Size(640, 0),
           duration: Duration(seconds: 1),
         );
@@ -610,6 +614,7 @@
 
       test('width = 0 -> 1.0', () {
         final value = VideoPlayerValue(
+          isInitialized: true,
           size: Size(0, 480),
           duration: Duration(seconds: 1),
         );
@@ -618,6 +623,7 @@
 
       test('negative aspect ratio -> 1.0', () {
         final value = VideoPlayerValue(
+          isInitialized: true,
           size: Size(640, -480),
           duration: Duration(seconds: 1),
         );
@@ -646,7 +652,7 @@
         File(''),
         videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true));
     await controller.initialize();
-    expect(controller.videoPlayerOptions.mixWithOthers, true);
+    expect(controller.videoPlayerOptions!.mixWithOthers, true);
   });
 }
 
@@ -706,7 +712,7 @@
   @override
   void seekTo(PositionMessage arg) {
     calls.add('seekTo');
-    _positions[arg.textureId] = Duration(milliseconds: arg.position);
+    _positions[arg.textureId!] = Duration(milliseconds: arg.position!);
   }
 
   @override
@@ -742,7 +748,7 @@
   int height;
   Duration duration;
   bool initWithError;
-  FakeEventsChannel eventsChannel;
+  late FakeEventsChannel eventsChannel;
 
   void onListen() {
     if (!initWithError) {
@@ -764,7 +770,7 @@
     eventsMethodChannel.setMockMethodCallHandler(onMethodCall);
   }
 
-  MethodChannel eventsMethodChannel;
+  late MethodChannel eventsMethodChannel;
   VoidCallback onListen;
 
   Future<dynamic> onMethodCall(MethodCall call) {
@@ -780,7 +786,7 @@
     _sendMessage(const StandardMethodCodec().encodeSuccessEnvelope(event));
   }
 
-  void sendError(String code, [String message, dynamic details]) {
+  void sendError(String code, [String? message, dynamic details]) {
     _sendMessage(const StandardMethodCodec().encodeErrorEnvelope(
       code: code,
       message: message,
@@ -794,6 +800,6 @@
     // available on all the versions of Flutter that we test.
     // ignore: deprecated_member_use
     defaultBinaryMessenger.handlePlatformMessage(
-        eventsMethodChannel.name, data, (ByteData data) {});
+        eventsMethodChannel.name, data, (ByteData? data) {});
   }
 }
diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md
index fea2357..748998f 100644
--- a/packages/video_player/video_player_platform_interface/CHANGELOG.md
+++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md
@@ -1,3 +1,15 @@
+## 3.0.0-nullsafety.2
+
+* Bump Dart SDK to support null safety.
+
+## 3.0.0-nullsafety.1
+
+* Make DataSource's `uri` parameter nullable.
+
+## 3.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 2.2.1
 
 * Update Flutter SDK constraint.
diff --git a/packages/video_player/video_player_platform_interface/analysis_options.yaml b/packages/video_player/video_player_platform_interface/analysis_options.yaml
new file mode 100644
index 0000000..3d64bb5
--- /dev/null
+++ b/packages/video_player/video_player_platform_interface/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: ../../../analysis_options.yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart
index bfe65f1..252cad6 100644
--- a/packages/video_player/video_player_platform_interface/lib/messages.dart
+++ b/packages/video_player/video_player_platform_interface/lib/messages.dart
@@ -1,13 +1,13 @@
-// Autogenerated from Pigeon (v0.1.7), do not edit directly.
+// Autogenerated from Pigeon (v0.1.12), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import
-// @dart = 2.8
+// @dart = 2.12
 import 'dart:async';
 import 'package:flutter/services.dart';
 import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
 
 class TextureMessage {
-  int textureId;
+  int? textureId;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -17,9 +17,6 @@
 
   // ignore: unused_element
   static TextureMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final TextureMessage result = TextureMessage();
     result.textureId = pigeonMap['textureId'];
     return result;
@@ -27,10 +24,10 @@
 }
 
 class CreateMessage {
-  String asset;
-  String uri;
-  String packageName;
-  String formatHint;
+  String? asset;
+  String? uri;
+  String? packageName;
+  String? formatHint;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -43,9 +40,6 @@
 
   // ignore: unused_element
   static CreateMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final CreateMessage result = CreateMessage();
     result.asset = pigeonMap['asset'];
     result.uri = pigeonMap['uri'];
@@ -56,8 +50,8 @@
 }
 
 class LoopingMessage {
-  int textureId;
-  bool isLooping;
+  int? textureId;
+  bool? isLooping;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -68,9 +62,6 @@
 
   // ignore: unused_element
   static LoopingMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final LoopingMessage result = LoopingMessage();
     result.textureId = pigeonMap['textureId'];
     result.isLooping = pigeonMap['isLooping'];
@@ -79,8 +70,8 @@
 }
 
 class VolumeMessage {
-  int textureId;
-  double volume;
+  int? textureId;
+  double? volume;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -91,9 +82,6 @@
 
   // ignore: unused_element
   static VolumeMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final VolumeMessage result = VolumeMessage();
     result.textureId = pigeonMap['textureId'];
     result.volume = pigeonMap['volume'];
@@ -102,8 +90,8 @@
 }
 
 class PlaybackSpeedMessage {
-  int textureId;
-  double speed;
+  int? textureId;
+  double? speed;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -114,9 +102,6 @@
 
   // ignore: unused_element
   static PlaybackSpeedMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final PlaybackSpeedMessage result = PlaybackSpeedMessage();
     result.textureId = pigeonMap['textureId'];
     result.speed = pigeonMap['speed'];
@@ -125,8 +110,8 @@
 }
 
 class PositionMessage {
-  int textureId;
-  int position;
+  int? textureId;
+  int? position;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -137,9 +122,6 @@
 
   // ignore: unused_element
   static PositionMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final PositionMessage result = PositionMessage();
     result.textureId = pigeonMap['textureId'];
     result.position = pigeonMap['position'];
@@ -148,7 +130,7 @@
 }
 
 class MixWithOthersMessage {
-  bool mixWithOthers;
+  bool? mixWithOthers;
   // ignore: unused_element
   Map<dynamic, dynamic> _toMap() {
     final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
@@ -158,9 +140,6 @@
 
   // ignore: unused_element
   static MixWithOthersMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
-    if (pigeonMap == null) {
-      return null;
-    }
     final MixWithOthersMessage result = MixWithOthersMessage();
     result.mixWithOthers = pigeonMap['mixWithOthers'];
     return result;
@@ -172,7 +151,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(null);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(null);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -194,7 +173,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -216,7 +195,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -238,7 +217,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -260,7 +239,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -283,7 +262,7 @@
         'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed',
         StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -305,7 +284,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -327,7 +306,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -349,7 +328,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -371,7 +350,7 @@
     const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
         'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -394,7 +373,7 @@
         'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers',
         StandardMessageCodec());
 
-    final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
+    final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
     if (replyMap == null) {
       throw PlatformException(
           code: 'channel-error',
@@ -424,131 +403,175 @@
   void seekTo(PositionMessage arg);
   void pause(TextureMessage arg);
   void setMixWithOthers(MixWithOthersMessage arg);
-  static void setup(TestHostVideoPlayerApi api) {
+  static void setup(TestHostVideoPlayerApi? api) {
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.initialize',
           StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        api.initialize();
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          api.initialize();
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final CreateMessage input = CreateMessage._fromMap(mapMessage);
-        final TextureMessage output = api.create(input);
-        return <dynamic, dynamic>{'result': output._toMap()};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final CreateMessage input = CreateMessage._fromMap(mapMessage);
+          final TextureMessage output = api.create(input);
+          return <dynamic, dynamic>{'result': output._toMap()};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final TextureMessage input = TextureMessage._fromMap(mapMessage);
-        api.dispose(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final TextureMessage input = TextureMessage._fromMap(mapMessage);
+          api.dispose(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.setLooping',
           StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final LoopingMessage input = LoopingMessage._fromMap(mapMessage);
-        api.setLooping(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final LoopingMessage input = LoopingMessage._fromMap(mapMessage);
+          api.setLooping(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.setVolume',
           StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final VolumeMessage input = VolumeMessage._fromMap(mapMessage);
-        api.setVolume(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final VolumeMessage input = VolumeMessage._fromMap(mapMessage);
+          api.setVolume(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed',
           StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final PlaybackSpeedMessage input =
-            PlaybackSpeedMessage._fromMap(mapMessage);
-        api.setPlaybackSpeed(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final PlaybackSpeedMessage input =
+              PlaybackSpeedMessage._fromMap(mapMessage);
+          api.setPlaybackSpeed(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final TextureMessage input = TextureMessage._fromMap(mapMessage);
-        api.play(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final TextureMessage input = TextureMessage._fromMap(mapMessage);
+          api.play(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final TextureMessage input = TextureMessage._fromMap(mapMessage);
-        final PositionMessage output = api.position(input);
-        return <dynamic, dynamic>{'result': output._toMap()};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final TextureMessage input = TextureMessage._fromMap(mapMessage);
+          final PositionMessage output = api.position(input);
+          return <dynamic, dynamic>{'result': output._toMap()};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final PositionMessage input = PositionMessage._fromMap(mapMessage);
-        api.seekTo(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final PositionMessage input = PositionMessage._fromMap(mapMessage);
+          api.seekTo(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final TextureMessage input = TextureMessage._fromMap(mapMessage);
-        api.pause(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final TextureMessage input = TextureMessage._fromMap(mapMessage);
+          api.pause(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
     {
       const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
           'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers',
           StandardMessageCodec());
-      channel.setMockMessageHandler((dynamic message) async {
-        final Map<dynamic, dynamic> mapMessage =
-            message as Map<dynamic, dynamic>;
-        final MixWithOthersMessage input =
-            MixWithOthersMessage._fromMap(mapMessage);
-        api.setMixWithOthers(input);
-        return <dynamic, dynamic>{};
-      });
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((dynamic message) async {
+          final Map<dynamic, dynamic> mapMessage =
+              message as Map<dynamic, dynamic>;
+          final MixWithOthersMessage input =
+              MixWithOthersMessage._fromMap(mapMessage);
+          api.setMixWithOthers(input);
+          return <dynamic, dynamic>{};
+        });
+      }
     }
   }
 }
diff --git a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart
index 0ea443f..9b007d0 100644
--- a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart
+++ b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart
@@ -26,7 +26,7 @@
   }
 
   @override
-  Future<int> create(DataSource dataSource) async {
+  Future<int?> create(DataSource dataSource) async {
     CreateMessage message = CreateMessage();
 
     switch (dataSource.sourceType) {
@@ -91,7 +91,7 @@
   Future<Duration> getPosition(int textureId) async {
     PositionMessage response =
         await _api.position(TextureMessage()..textureId = textureId);
-    return Duration(milliseconds: response.position);
+    return Duration(milliseconds: response.position!);
   }
 
   @override
diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart
index 2757fb1..f2bc002 100644
--- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart
+++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart
@@ -7,7 +7,7 @@
 
 import 'package:flutter/foundation.dart';
 import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart' show required, visibleForTesting;
+import 'package:meta/meta.dart' show visibleForTesting;
 
 import 'method_channel_video_player.dart';
 
@@ -66,7 +66,7 @@
   }
 
   /// Creates an instance of a video player and returns its textureId.
-  Future<int> create(DataSource dataSource) {
+  Future<int?> create(DataSource dataSource) {
     throw UnimplementedError('create() has not been implemented.');
   }
 
@@ -146,7 +146,7 @@
   /// The [package] argument must be non-null when the asset comes from a
   /// package and null otherwise.
   DataSource({
-    @required this.sourceType,
+    required this.sourceType,
     this.uri,
     this.formatHint,
     this.asset,
@@ -163,18 +163,18 @@
   ///
   /// This will be in different formats depending on the [DataSourceType] of
   /// the original video.
-  final String uri;
+  final String? uri;
 
   /// **Android only**. Will override the platform's generic file format
   /// detection with whatever is set here.
-  final VideoFormat formatHint;
+  final VideoFormat? formatHint;
 
   /// The name of the asset. Only set for [DataSourceType.asset] videos.
-  final String asset;
+  final String? asset;
 
   /// The package that the asset was loaded from. Only set for
   /// [DataSourceType.asset] videos.
-  final String package;
+  final String? package;
 }
 
 /// The way in which the video was originally loaded.
@@ -216,7 +216,7 @@
   /// Depending on the [eventType], the [duration], [size] and [buffered]
   /// arguments can be null.
   VideoEvent({
-    @required this.eventType,
+    required this.eventType,
     this.duration,
     this.size,
     this.buffered,
@@ -228,17 +228,17 @@
   /// Duration of the video.
   ///
   /// Only used if [eventType] is [VideoEventType.initialized].
-  final Duration duration;
+  final Duration? duration;
 
   /// Size of the video.
   ///
   /// Only used if [eventType] is [VideoEventType.initialized].
-  final Size size;
+  final Size? size;
 
   /// Buffered parts of the video.
   ///
   /// Only used if [eventType] is [VideoEventType.bufferingUpdate].
-  final List<DurationRange> buffered;
+  final List<DurationRange>? buffered;
 
   @override
   bool operator ==(Object other) {
diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml
index 0c1dcad..de35d59 100644
--- a/packages/video_player/video_player_platform_interface/pubspec.yaml
+++ b/packages/video_player/video_player_platform_interface/pubspec.yaml
@@ -3,19 +3,19 @@
 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 2.2.1
+version: 3.0.0-nullsafety.2
 
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.0.5
+  meta: ^1.3.0-nullsafety.3
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
   mockito: ^4.1.1
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.8.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.10.0"
diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart
index c479100..5c19ebc 100644
--- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart
+++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(egarciad): Remove once Mockito is migrated to null safety.
+// @dart = 2.9
+
 import 'dart:ui';
 
 import 'package:flutter/services.dart';
diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md
index cbb07e8..52c2042 100644
--- a/packages/video_player/video_player_web/CHANGELOG.md
+++ b/packages/video_player/video_player_web/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 2.0.0-nullsafety.1
+
+* Bump Dart SDK to support null safety.
+
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+
 ## 0.1.4+2
 
 * Update Flutter SDK constraint.
diff --git a/packages/video_player/video_player_web/analysis_options.yaml b/packages/video_player/video_player_web/analysis_options.yaml
new file mode 100644
index 0000000..7e5b7b3
--- /dev/null
+++ b/packages/video_player/video_player_web/analysis_options.yaml
@@ -0,0 +1,12 @@
+# This is a temporary file to allow us to unblock the flutter/plugins repo CI.
+# It disables some of lints that were disabled inline. Disabling lints inline
+# is no longer possible, so this file is required.
+# TODO(ditman) https://github.com/flutter/flutter/issues/55000 (clean this up)
+
+include: ../../../analysis_options.yaml
+
+analyzer:
+  enable-experiment:
+    - non-nullable
+  errors:
+    undefined_prefixed_name: ignore
diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart
index 6715d5a..de8f6a7 100644
--- a/packages/video_player/video_player_web/lib/video_player_web.dart
+++ b/packages/video_player/video_player_web/lib/video_player_web.dart
@@ -50,7 +50,7 @@
 
   @override
   Future<void> dispose(int textureId) async {
-    _videoPlayers[textureId].dispose();
+    _videoPlayers[textureId]!.dispose();
     _videoPlayers.remove(textureId);
     return null;
   }
@@ -66,16 +66,16 @@
     final int textureId = _textureCounter;
     _textureCounter++;
 
-    String uri;
+    late String uri;
     switch (dataSource.sourceType) {
       case DataSourceType.network:
         // Do NOT modify the incoming uri, it can be a Blob, and Safari doesn't
         // like blobs that have changed.
-        uri = dataSource.uri;
+        uri = dataSource.uri ?? '';
         break;
       case DataSourceType.asset:
-        String assetUrl = dataSource.asset;
-        if (dataSource.package != null && dataSource.package.isNotEmpty) {
+        String assetUrl = dataSource.asset!;
+        if (dataSource.package != null && dataSource.package!.isNotEmpty) {
           assetUrl = 'packages/${dataSource.package}/$assetUrl';
         }
         assetUrl = ui.webOnlyAssetManager.getAssetUrl(assetUrl);
@@ -99,45 +99,45 @@
 
   @override
   Future<void> setLooping(int textureId, bool looping) async {
-    return _videoPlayers[textureId].setLooping(looping);
+    return _videoPlayers[textureId]!.setLooping(looping);
   }
 
   @override
   Future<void> play(int textureId) async {
-    return _videoPlayers[textureId].play();
+    return _videoPlayers[textureId]!.play();
   }
 
   @override
   Future<void> pause(int textureId) async {
-    return _videoPlayers[textureId].pause();
+    return _videoPlayers[textureId]!.pause();
   }
 
   @override
   Future<void> setVolume(int textureId, double volume) async {
-    return _videoPlayers[textureId].setVolume(volume);
+    return _videoPlayers[textureId]!.setVolume(volume);
   }
 
   @override
   Future<void> setPlaybackSpeed(int textureId, double speed) async {
     assert(speed > 0);
 
-    return _videoPlayers[textureId].setPlaybackSpeed(speed);
+    return _videoPlayers[textureId]!.setPlaybackSpeed(speed);
   }
 
   @override
   Future<void> seekTo(int textureId, Duration position) async {
-    return _videoPlayers[textureId].seekTo(position);
+    return _videoPlayers[textureId]!.seekTo(position);
   }
 
   @override
   Future<Duration> getPosition(int textureId) async {
-    _videoPlayers[textureId].sendBufferingUpdate();
-    return _videoPlayers[textureId].getPosition();
+    _videoPlayers[textureId]!.sendBufferingUpdate();
+    return _videoPlayers[textureId]!.getPosition();
   }
 
   @override
   Stream<VideoEvent> videoEventsFor(int textureId) {
-    return _videoPlayers[textureId].eventController.stream;
+    return _videoPlayers[textureId]!.eventController.stream;
   }
 
   @override
@@ -147,14 +147,14 @@
 }
 
 class _VideoPlayer {
-  _VideoPlayer({this.uri, this.textureId});
+  _VideoPlayer({required this.uri, required this.textureId});
 
   final StreamController<VideoEvent> eventController =
       StreamController<VideoEvent>();
 
   final String uri;
   final int textureId;
-  VideoElement videoElement;
+  late VideoElement videoElement;
   bool isInitialized = false;
 
   void initialize() {
@@ -183,9 +183,9 @@
       // The Event itself (_) doesn't contain info about the actual error.
       // We need to look at the HTMLMediaElement.error.
       // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/error
-      MediaError error = videoElement.error;
+      MediaError error = videoElement.error!;
       eventController.addError(PlatformException(
-        code: _kErrorValueToErrorName[error.code],
+        code: _kErrorValueToErrorName[error.code]!,
         message: error.message != '' ? error.message : _kDefaultErrorMessage,
         details: _kErrorValueToErrorDescription[error.code],
       ));
@@ -258,8 +258,8 @@
           milliseconds: (videoElement.duration * 1000).round(),
         ),
         size: Size(
-          videoElement.videoWidth.toDouble() ?? 0.0,
-          videoElement.videoHeight.toDouble() ?? 0.0,
+          videoElement.videoWidth.toDouble(),
+          videoElement.videoHeight.toDouble(),
         ),
       ),
     );
diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml
index 37cadbd..ffbf1ea 100644
--- a/packages/video_player/video_player_web/pubspec.yaml
+++ b/packages/video_player/video_player_web/pubspec.yaml
@@ -4,7 +4,11 @@
 # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump
 # the version to 2.0.0.
 # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
+<<<<<<< HEAD
+version: 2.0.0-nullsafety.1
+=======
 version: 0.1.4+2
+>>>>>>> master
 
 flutter:
   plugin:
@@ -18,16 +22,16 @@
     sdk: flutter
   flutter_web_plugins:
     sdk: flutter
-  meta: ^1.1.7
-  video_player_platform_interface: ^2.2.0
+  meta: ^1.3.0-nullsafety.3
+  video_player_platform_interface: ^3.0.0-nullsafety.1
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
   video_player:
     path: ../video_player
-  pedantic: ^1.8.0
+  pedantic: ^1.10.0-nullsafety.1
 
 environment:
-  sdk: ">=2.8.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.12.8"
diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart
index 453079b..c433d82 100644
--- a/packages/video_player/video_player_web/test/video_player_web_test.dart
+++ b/packages/video_player/video_player_web/test/video_player_web_test.dart
@@ -14,16 +14,16 @@
 
 void main() {
   group('VideoPlayer for Web', () {
-    int textureId;
+    late int textureId;
 
     setUp(() async {
       VideoPlayerPlatform.instance = VideoPlayerPlugin();
-      textureId = await VideoPlayerPlatform.instance.create(
+      textureId = (await VideoPlayerPlatform.instance.create(
         DataSource(
             sourceType: DataSourceType.network,
             uri:
                 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'),
-      );
+      ))!;
     });
 
     test('$VideoPlayerPlugin is the live instance', () {
@@ -84,12 +84,12 @@
     });
 
     test('throws PlatformException when playing bad media', () async {
-      int videoPlayerId = await VideoPlayerPlatform.instance.create(
+      int videoPlayerId = (await VideoPlayerPlatform.instance.create(
         DataSource(
             sourceType: DataSourceType.network,
             uri:
                 'https://flutter.github.io/assets-for-api-docs/assets/videos/_non_existent_video.mp4'),
-      );
+      ))!;
 
       Stream<VideoEvent> eventStream =
           VideoPlayerPlatform.instance.videoEventsFor(videoPlayerId);
diff --git a/script/incremental_build.sh b/script/incremental_build.sh
index 671ce66..95e42c4 100755
--- a/script/incremental_build.sh
+++ b/script/incremental_build.sh
@@ -29,6 +29,16 @@
 #
 # TODO(mklim): Remove everything from this list. https://github.com/flutter/flutter/issues/45440
 CUSTOM_ANALYSIS_PLUGINS=(
+  "plugin_platform_interface"
+  "video_player/video_player"
+  "video_player/video_player_platform_interface"
+  "video_player/video_player_web"
+  "url_launcher/url_launcher_platform_interface"
+  "url_launcher/url_launcher"
+  "device_info/device_info_platform_interface"
+  "device_info/device_info"
+  "connectivity/connectivity_platform_interface"
+  "connectivity/connectivity"
 )
 # Comma-separated string of the list above
 readonly CUSTOM_FLAG=$(IFS=, ; echo "${CUSTOM_ANALYSIS_PLUGINS[*]}")
@@ -61,6 +71,7 @@
     echo running "${ACTIONS[@]}"
     (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]})
     echo "Running version check for changed packages"
-    (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)")
+    # TODO(egarciad): Enable this check once in master.
+    # (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)")
   fi
 fi
diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh
index 5d167d7..dc82e25 100644
--- a/script/nnbd_plugins.sh
+++ b/script/nnbd_plugins.sh
@@ -5,7 +5,15 @@
 # null-safe is available on stable.
 
 readonly NNBD_PLUGINS_LIST=(
+  "connectivity"
+  "device_info"
   "flutter_webview"
+  "google_sign_in"
+  "local_auth"
+  "path_provider"
+  "plugin_platform_interface"
+  "url_launcher"
+  "video_player"
 )
 
 export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}")