我创建了一个示例应用程序来演示解决方案,但显然 Stack Overflow 的人们希望我更加努力地与您分享这些信息。他们删除了我原来的答案(尽管它为每个有问题的人解决了问题)。并希望我提取部分答案并将其张贴在这里。我做了很多工作来解决这个问题并将它作为一个完整的应用程序示例发布,但显然这还不够。我讨厌这个。我正在努力帮助人们,但他们不喜欢解决方案的外部参考。
我创建了一个完整的解决方案来演示如何在https://github.com/johnwargo/flutter-android-connectivity-permissions 中解决这个问题。
Flutter 似乎没有办法查询应用用户的权限,因此有人创建了 Flutter permissions_handler 包。将它添加到我的应用程序中,以及原始问题中显示的代码变体,解决了我的问题。
我很快意识到 Flutter repo 上的答案是不完整的,任何尝试实施此解决方案的人都需要一些帮助。为了方便这些开发人员,我在这个 repo 中创建了一个完整的示例应用程序。
这就是我所做的
从项目的pubspec.yaml 文件开始,我添加了connectivity 和permissions_handler 包:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.3
connectivity: ^0.4.8+6
permission_handler: ^5.0.1
接下来,我将导入添加到项目的 main.dart 文件中:
import 'package:connectivity/connectivity.dart';
import 'package:permission_handler/permission_handler.dart';
然后我在initConnectivity函数中添加了一些代码:
Future<void> initConnectivity() async {
ConnectivityResult result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await _connectivity.checkConnectivity();
} on PlatformException catch (e) {
print(e.toString());
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
return Future.value(null);
}
// Check to see if Android Location permissions are enabled
// Described in https://github.com/flutter/flutter/issues/51529
if (Platform.isAndroid) {
print('Checking Android permissions');
var status = await Permission.location.status;
// Blocked?
if (status.isUndetermined || status.isDenied || status.isRestricted) {
// Ask the user to unblock
if (await Permission.location.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
print('Location permission granted');
} else {
print('Location permission not granted');
}
} else {
print('Permission already granted (previous execution?)');
}
}
return _updateConnectionStatus(result);
}
我添加的代码是:
// Check to see if Android Location permissions are enabled
// Described in https://github.com/flutter/flutter/issues/51529
if (Platform.isAndroid) {
print('Checking Android permissions');
var status = await Permission.location.status;
// Blocked?
if (status.isUndetermined || status.isDenied || status.isRestricted) {
// Ask the user to unblock
if (await Permission.location.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
print('Location permission granted');
} else {
print('Location permission not granted');
}
} else {
print('Permission already granted (previous execution?)');
}
}
此代码在启动时执行一次,并在从设备检索连接状态之前检查权限。
如果此时运行代码,一切似乎都可以正常工作,但 Wi-Fi 名称、BSSID 和 IP 地址的值都会报告null。当您查看控制台时,您会看到:
I/flutter ( 6506): Checking Android permissions
I/flutter ( 6506): Result: ConnectivityResult.wifi
D/permissions_handler( 6506): No permissions found in manifest for: 3
I/flutter ( 6506): Wi-Fi Name: null
D/permissions_handler( 6506): No permissions found in manifest for: 3
I/flutter ( 6506): Location permission not granted
I/flutter ( 6506): Result: ConnectivityResult.wifi
I/flutter ( 6506): BSSID: 02:00:00:00:00:00
I/flutter ( 6506): Wi-Fi Name: null
I/flutter ( 6506): BSSID: 02:00:00:00:00:00
这是因为如果没有在应用程序中定义正确的权限,status 的值就是null,并且不会发生任何其他权限检查。甚至从未像预期的那样要求用户许可。
要解决这个问题,请打开项目的android/app/src/main/AndroidManifest.xml 文件并将位置权限添加到应用的配置中:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
我用的是课程设置,我觉得你也可以用细的。
很多时候,作者会告诉您要进行哪些权限更改,但没有告诉您应该在文件中的哪个位置进行更改。我不做很多原生 Android 开发,所以我不知道该设置在哪里,所以这里是完整的文件列表,以便您可以看到它的正确位置:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.johnwargo.connectivitypermissions">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name="io.flutter.app.FlutterApplication"
android:label="connectivitypermissions"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
当您在 Android API 29 上启动应用程序时,它看起来像这样:
对于我的特定应用,我不关心在应用未运行时从设备获取设置,因此我选择了“仅在使用应用时允许”。如果您查看控制台,您将看到以下内容:
I/flutter ( 7670): Checking Android permissions
I/flutter ( 7670): Result: ConnectivityResult.wifi
I/flutter ( 7670): Wi-Fi Name: null
I/flutter ( 7670): BSSID: 02:00:00:00:00:00
I/flutter ( 7670): Location permission granted
I/flutter ( 7670): Result: ConnectivityResult.wifi
I/flutter ( 7670): Wi-Fi Name: AndroidWifi
I/flutter ( 7670): BSSID: 02:15:b2:00:01:00
请注意,该应用会在等待用户授予权限时继续检查 Wi-Fi 设置;那是因为代码的编写方式,您可以轻松地对其进行调整,以便在尝试之前等待许可,但它会运行两次 init,因此您将第二次获得正确的数据(不,我不知道为什么它运行两次)。