我正在开发一个应用程序,每当我通过扫描连接到它时,该应用程序都可以共享文件,它在目标 sdk 版本 29 及更高版本上无法连接,但在目标 sdk 版本 28 上运行良好。这种情况仅发生在 android 10 上。请帮助我。它在所有 android 9 及更高版本上运行良好,但在 android 10 版本上不起作用。我该怎么办,请建议我,我正在遭受这种痛苦。请帮助我,我将非常感激。
This is my manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.Anand.ShareMe">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS"
tools:ignore="ProtectedPermissions" />
<application
android:name="com.Anand.ShareMe.base.App"
android:allowBackup="true"
android:appComponentFactory="@string/app_name"
android:fullBackupContent="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.TBShare"
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:appComponentFactory">
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="@string/admob_app_id" />
<activity
android:name="com.Anand.ShareMe.activity.MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.TBShare.NoActionBar">
</activity>
<activity
android:name="com.Anand.ShareMe.activity.ShareActivity"
android:label="@string/app_name"
android:theme="@style/Theme.TBShare.NoActionBar.StaticStatusBar">
<intent-filter>
<action android:name="genonbeta.intent.action.TBShare_SEND_TEXT" />
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<action android:name="genonbeta.intent.action.TBShare_SEND" />
<action android:name="genonbeta.intent.action.TBShare_SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
<activity
android:name="com.Anand.ShareMe.activity.AddDevicesToTransferActivity"
android:label="@string/text_addDevicesToTransfer"
android:theme="@style/Theme.TBShare.NoActionBar.StaticStatusBar" />
<activity
android:name="com.Anand.ShareMe.activity.FileExplorerActivity"
android:label="@string/text_fileExplorer"
android:theme="@style/Theme.TBShare.NoActionBar.StaticStatusBar" />
<activity
android:name="com.Anand.ShareMe.activity.ConnectionManagerActivity"
android:label="@string/text_connectDevices"
android:theme="@style/Theme.TBShare.NoActionBar.StaticStatusBar" />
<activity
android:name="com.Anand.ShareMe.activity.ContentSharingActivity"
android:label="@string/text_send"
android:launchMode="singleTask"
android:theme="@style/Theme.TBShare.NoActionBar.StaticStatusBar" />
<activity
android:name="com.Anand.ShareMe.activity.FilePickerActivity"
android:label="@string/text_fileExplorer" />
<activity
android:name="com.Anand.ShareMe.activity.ViewTransferActivity"
android:label="@string/text_transactionViewer"
android:theme="@style/Theme.TBShare.NoActionBar.StaticStatusBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.tshare" />
<data android:pathPattern=".*\\..*\\.tshare" />
</intent-filter>
</activity>
<activity
android:name="com.Anand.ShareMe.activity.ManageDevicesActivity"
android:label="@string/text_manageDevices"
android:theme="@style/Theme.TBShare.NoActionBar"/>
<activity
android:name="com.Anand.ShareMe.activity.SearchActivity"
android:label="@string/butn_search" />
<activity
android:name="com.Anand.ShareMe.activity.TextEditorActivity"
android:label="@string/text_textEditor" />
<activity
android:name="com.Anand.ShareMe.activity.ChangeStoragePathActivity"
android:theme="@style/Base.Theme.AppCompat.Dialog">
<intent-filter>
<action android:name="com.genonbeta.intent.action.UPDATE_STORAGE_PATH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.Anand.ShareMe.activity.BarcodeScannerActivity"
android:label="@string/text_scanQrCode"
android:theme="@style/Theme.TBShare.BarcodeScannerActivity" />
<activity
android:name="com.Anand.ShareMe.activity.SplashActivity"
android:label="@string/app_name"
android:theme="@style/Theme.TBShare.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.Anand.ShareMe.activity.WebShareActivity"
android:label="Web Share"
android:theme="@style/Theme.TBShare.NoActionBar"/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<receiver
android:name="com.Anand.ShareMe.receiver.NetworkStatusReceiver"
android:process=":transfer">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<action android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<action android:name="android.net.wifi.STATE_CHANGE" />
<action android:name="android.net.wifi.p2p.CONNECTION_STATE_CHANGE" />
</intent-filter>
</receiver>
<receiver
android:name="com.Anand.ShareMe.receiver.DialogEventReceiver"
android:process=":transfer" />
<service
android:name="com.Anand.ShareMe.service.CommunicationService"
android:enabled="true"
android:label="@string/text_communicationService"
android:process=":transfer" />
<service
android:name="com.Anand.ShareMe.service.DeviceChooserService"
android:label="@string/text_chooserTargetService"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
<service android:name="com.Anand.ShareMe.service.DeviceScannerService">
<intent-filter>
<action android:name="genonbeta.intent.action.SCAN_DEVICES" />
<action android:name="genonbeta.intent.action.ADD_IP" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
<service
android:name="com.Anand.ShareMe.service.WorkerService"
android:label="@string/text_workerService" />
<service
android:name="com.Anand.ShareMe.service.CommunicationToggleTile"
android:icon="@mipmap/ic_launcher"
android:label="@string/text_shareFiles"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:process=":transfer">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
</application>
</manifest>
这是我的 ConnectionUtill 代码
package com.Anand.ShareMe.util;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.util.Log;
import androidx.annotation.WorkerThread;
import androidx.core.content.ContextCompat;
import com.Anand.ShareMe.base.AppConfig;
import com.Anand.ShareMe.adapter.NetworkDeviceListAdapter;
import com.genonbeta.android.framework.util.Interrupter;
import java.util.List;
public class ConnectionUtils
{
public static final String TAG = ConnectionUtils.class.getSimpleName();
private Context mContext;
private WifiManager mWifiManager;
private HotspotUtils mHotspotUtils;
private LocationManager mLocationManager;
private ConnectivityManager mConnectivityManager;
ConnectionUtils(Context context) {
mContext = context;
mWifiManager = (WifiManager) getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mLocationManager = (LocationManager) getContext().getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
mHotspotUtils = HotspotUtils.getInstance(getContext());
mConnectivityManager = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
}
public static ConnectionUtils getInstance(Context context) {
return new ConnectionUtils(context);
}
public static String getCleanNetworkName(String networkName) {
if (networkName == null)
return "";
return networkName.replace("\"", "");
}
public boolean canAccessLocation() {
return hasLocationPermission(getContext()) && isLocationServiceEnabled();
}
public boolean canReadScanResults() {
return getWifiManager().isWifiEnabled() && (Build.VERSION.SDK_INT < 23 || canAccessLocation());
}
public boolean disableCurrentNetwork() {
// TODO: Networks added by other applications will possibly reconnect even if we disconnect them
// This is because we are only allowed to manipulate the connections that we added.
// And if it is the case, then the return value of disableNetwork will be false.
return isConnectedToAnyNetwork()
&& getWifiManager().disconnect()
&& getWifiManager().disableNetwork(getWifiManager().getConnectionInfo().getNetworkId());
}
@WorkerThread
public String establishHotspotConnection(final Interrupter interrupter,
final NetworkDeviceListAdapter.HotspotNetwork hotspotNetwork,
final ConnectionCallback connectionCallback) {
final int pingTimeout = 1000; // ms
final long startTime = System.currentTimeMillis();
String remoteAddress = null;
boolean connectionToggled = false;
boolean secondAttempt = false;
boolean thirdAttempt = false;
while (true) {
int passedTime = (int) (System.currentTimeMillis() - startTime);
// retry code will be here.
if (passedTime >= 10000 && !secondAttempt) {
secondAttempt = true;
disableCurrentNetwork();
connectionToggled = false;
}
if (passedTime >= 20000 && !thirdAttempt) {
thirdAttempt = true;
disableCurrentNetwork();
connectionToggled = false;
}
if (!getWifiManager().isWifiEnabled()) {
Log.d(TAG, "establishHotspotConnection(): Wifi is off. Making a request to turn it on");
if (!getWifiManager().setWifiEnabled(true)) {
Log.d(TAG, "establishHotspotConnection(): Wifi was off. The request has failed. Exiting.");
break;
}
} else if (!isConnectedToNetwork(hotspotNetwork) && !connectionToggled) {
Log.d(TAG, "establishHotspotConnection(): Requested network toggle");
toggleConnection(hotspotNetwork);
connectionToggled = true;
} else {
Log.d(TAG, "establishHotspotConnection(): Waiting to connect to the server");
final DhcpInfo routeInfo = getWifiManager().getDhcpInfo();
//Log.w(TAG, String.format("establishHotspotConnection(): DHCP: %s", routeInfo));
if (routeInfo != null && routeInfo.gateway != 0) {
final String testedRemoteAddress = NetworkUtils.convertInet4Address(routeInfo.gateway);
Log.d(TAG, String.format("establishHotspotConnection(): DhcpInfo: gateway: %s dns1: %s dns2: %s ipAddr: %s serverAddr: %s netMask: %s",
testedRemoteAddress,
NetworkUtils.convertInet4Address(routeInfo.dns1),
NetworkUtils.convertInet4Address(routeInfo.dns2),
NetworkUtils.convertInet4Address(routeInfo.ipAddress),
NetworkUtils.convertInet4Address(routeInfo.serverAddress),
NetworkUtils.convertInet4Address(routeInfo.netmask)));
Log.d(TAG, "establishHotspotConnection(): There is DHCP info provided waiting to reach the address " + testedRemoteAddress);
/*if (NetworkUtils.ping(testedRemoteAddress, pingTimeout)) {
Log.d(TAG, "establishHotspotConnection(): AP has been reached. Returning OK state.");
remoteAddress = testedRemoteAddress;
break;
} else
Log.d(TAG, "establishHotspotConnection(): Connection check ping failed");*/
if (UIConnectionUtils.isOSAbove(Build.VERSION_CODES.P)
? NetworkUtils.ping(testedRemoteAddress, pingTimeout)
: NetworkUtils.ping(testedRemoteAddress)) {
Log.d(TAG, "establishHotspotConnection(): AP has been reached. Returning OK state.");
remoteAddress = testedRemoteAddress;
break;
} else
Log.d(TAG, "establishHotspotConnection(): Connection check ping failed");
} else
Log.d(TAG, "establishHotspotConnection(): No DHCP provided. Looping...");
}
if (connectionCallback.onTimePassed(1000, passedTime) || interrupter.interrupted()) {
Log.d(TAG, "establishHotspotConnection(): Timed out or onTimePassed returned true. Exiting...");
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
return remoteAddress;
}
public boolean hasLocationPermission(Context context) {
return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
public Context getContext() {
return mContext;
}
public ConnectivityManager getConnectivityManager() {
return mConnectivityManager;
}
public HotspotUtils getHotspotUtils() {
return mHotspotUtils;
}
public LocationManager getLocationManager() {
return mLocationManager;
}
public WifiManager getWifiManager() {
return mWifiManager;
}
public boolean isConnectionSelfNetwork() {
WifiInfo wifiInfo = getWifiManager().getConnectionInfo();
return wifiInfo != null
&& getCleanNetworkName(wifiInfo.getSSID()).startsWith(AppConfig.PREFIX_ACCESS_POINT);
}
public boolean isConnectedToAnyNetwork() {
NetworkInfo info = getConnectivityManager().getActiveNetworkInfo();
return info != null
&& info.getType() == ConnectivityManager.TYPE_WIFI
&& info.isConnected();
}
public boolean isConnectedToNetwork(NetworkDeviceListAdapter.HotspotNetwork hotspotNetwork) {
if (!isConnectedToAnyNetwork())
return false;
if (hotspotNetwork.BSSID != null)
return hotspotNetwork.BSSID.equals(getWifiManager().getConnectionInfo().getBSSID());
return hotspotNetwork.SSID.equals(getCleanNetworkName(getWifiManager().getConnectionInfo().getSSID()));
}
public boolean isLocationServiceEnabled() {
return mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
public boolean isMobileDataActive() {
return mConnectivityManager.getActiveNetworkInfo() != null
&& mConnectivityManager.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_MOBILE;
}
public boolean toggleConnection(NetworkDeviceListAdapter.HotspotNetwork hotspotNetwork) {
if (!isConnectedToNetwork(hotspotNetwork)) {
if (isConnectedToAnyNetwork())
disableCurrentNetwork();
/*WifiConfiguration config = new WifiConfiguration();
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();*/
WifiConfiguration config = new WifiConfiguration();
config.SSID = String.format("\"%s\"", hotspotNetwork.SSID);
switch (hotspotNetwork.keyManagement) {
case 0: // OPEN
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
break;
case 1: // WEP64
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
if (hotspotNetwork.password != null
&& hotspotNetwork.password.matches("[0-9A-Fa-f]*")) {
config.wepKeys[0] = hotspotNetwork.password;
} else {
//fail("Please type hex pair for the password");
}
break;
case 2: // WEP128
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
if (hotspotNetwork.password != null
&& hotspotNetwork.password.matches("[0-9A-Fa-f]*")) {
config.wepKeys[0] = hotspotNetwork.password;
} else {
//fail("Please type hex pair for the password");
}
break;
case 3: // WPA_TKIP
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
if (hotspotNetwork.password != null
&& hotspotNetwork.password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = hotspotNetwork.password;
} else {
config.preSharedKey = '"' + hotspotNetwork.password + '"';
}
break;
case 4: // WPA2_AES
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
if (hotspotNetwork.password != null
&& hotspotNetwork.password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = hotspotNetwork.password;
} else {
config.preSharedKey = '"' + hotspotNetwork.password + '"';
}
break;
}
/*
old wifi connectivity code works for below M
int netId = getWifiManager().addNetwork(config);
getWifiManager().disconnect();
getWifiManager().enableNetwork(netId, true);
return getWifiManager().reconnect();*/
try {
int netId = getWifiManager().addNetwork(config);
if (/*Build.VERSION.SDK_INT >= */UIConnectionUtils.isOSAbove(Build.VERSION_CODES.M)) {
List<WifiConfiguration> list = getWifiManager().getConfiguredNetworks();
for (WifiConfiguration hotspotWifi : list) {
if (hotspotWifi.SSID != null && hotspotWifi.SSID.equalsIgnoreCase(config.SSID)) {
getWifiManager().disconnect();
getWifiManager().enableNetwork(hotspotWifi.networkId, true);
return getWifiManager().reconnect();
}
}
} else {
getWifiManager().disconnect();
getWifiManager().enableNetwork(netId, true);
return getWifiManager().reconnect();
}
} catch (Exception exp) {
disableCurrentNetwork();
return false;
}
}
disableCurrentNetwork();
return false;
}
public interface ConnectionCallback {
boolean onTimePassed(int delimiter, long timePassed);
}
}
您尚未请求运行时权限
android.Manifest.permission.ACCESS_COARSE_LOCATION
和android.Manifest.permission.ACCESS_FINE_LOCATION
,这就是您收到错误的原因。
您可以通过以下方式请求权限:
这是kotlin中的代码:
override fun onCreate(savedInstanceState: Bundle?) {
// ...
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
startUseLocationService()
} else {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
requestLocationPermission)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == requestLocationPermission) {
if (grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
startUseLocationService()
} else {
Toast.makeText(this, "Failed to request the location permissions", Toast.LENGTH_SHORT).show()
}
}
}
在清单中指定位置权限是不够的,您还需要实际请求它(就像您对
WRITE_EXTERNAL_STORAGE
和 READ_PHONE_STATE
所做的那样)。
这就是您在日志中看到 SecurityException: UID 10293 has no location permission
的原因。
您偶然发现的确实是Android 10 中的新功能。 请注意,这只是记录的错误here。 您的应用程序不应崩溃,它只会从
getConfiguredNetworks
接收一个空列表(并打印这些日志)。
但是,一旦您成功请求权限,您可能最终会被下一个检查抓住(除非您的应用程序是运营商应用程序)。 因此,您可能需要重新考虑是否要以 API 29 为目标(从长远来看不现实)或考虑其他解决方案来实现您的功能。