当应用程序处于后台时,WifiP2pManager 无法添加本地服务和发现服务 returns WifiP2pManager.Error
WifiP2pManager failed to addLocalService and discoverServices returns WifiP2pManager.Error when application is in background
我是新来的。无论如何,我一直在为这个问题挠头。我创建了一个 运行s WiFiP2pHelper 的服务来发现附近的设备并检索 WifiP2pDnsSdServiceInfo。我在多部手机上测试过,它们似乎都可以正常工作。如果它工作正常,它应该 return 记录如下:
2020-08-12 13:32:23.449 24345-24345/com.example.acts D/WiFi P2P Helper: Service Request Added
2020-08-12 13:32:23.449 24345-24345/com.example.acts D/WiFi P2P Helper: Discover Services Successful
2020-08-12 13:32:23.473 24345-24345/com.example.acts D/WiFi P2P Helper: Local Service Added
现在我在后台为 运行 提供服务(即使应用程序被终止)。它似乎在我测试过的设备上运行良好,除了 Android 10 上的任何 运行s。我怀疑是 Android 10 导致 WiFiP2pManager 或 WiFi P2P 本身不 运行 在后台。但我不完全确定它是否是 Android 10 引起的(我只有 2 Android 10 个设备进行了测试)。它 return 包含以下日志:
2020-08-12 13:33:23.517 24345-24345/com.example.acts D/WiFi P2P Helper: Service Request Added
2020-08-12 13:33:23.517 24345-24345/com.example.acts D/WiFi P2P Helper: Error with P2P 0
2020-08-12 13:33:23.518 24345-24345/com.example.acts D/WiFi P2P Helper: Failed to Add Local Service
2020-08-12 13:33:23.518 24345-24345/com.example.acts E/WiFi P2P Helper: 0
如您所见,“Error with P2P 0”和“Failed to Add Local Service”指向discoverServices和addLocalService。下面是代码。很抱歉把它全部转储在这里。任何帮助将不胜感激!谢谢!
public class WiFiP2PHelper extends Service {
WifiP2pManager manager;
WifiP2pManager.Channel channel;
WifiP2pDnsSdServiceRequest serviceRequest;
IntentFilter intentFilter;
String iid;
private String baseServiceName = "ACTS";
private String serviceName = "";
final HashMap<String, String> buddies = new HashMap<String, String>();
final String TAG = "WiFi P2P Helper";
Handler handler = new Handler();
Runnable runnable;
int delay = 15000;
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onCreate() {
super.onCreate();
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
getUser();
startRegistration();
discoverService();
startMyOwnForeground();
return START_STICKY;
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground() {
String NOTIFICATION_CHANNEL_ID = "com.example.acts";
String channelName = "My Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Hello World")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(1333, notification);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void getUser() {
List<User> users = User.getUser();
int count = users.size();
if (count > 0) {
User loggedInUser = users.get(0);
iid = loggedInUser.Id;
serviceName = baseServiceName + "_" + loggedInUser.Id;
Log.e("User", iid);
} else {
//uId = "User_Unregistered";
serviceName = baseServiceName + "_User_Unregistered";
Log.e("User in else", serviceName);
}
}
public String getWFDMacAddress() {
try {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface ntwInterface : interfaces) {
if (ntwInterface.getName().equalsIgnoreCase("p2p0")) {
byte[] byteMac = ntwInterface.getHardwareAddress();
if (byteMac == null) {
return null;
}
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < byteMac.length; i++) {
strBuilder.append(String.format("%02X:", byteMac[i]));
}
if (strBuilder.length() > 0) {
strBuilder.deleteCharAt(strBuilder.length() - 1);
}
return strBuilder.toString().toLowerCase();
}
}
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
public int findOpenSocket() throws IOException {
// Initialize a server socket on the next available port.
ServerSocket serverSocket = new ServerSocket(0);
// Store the chosen port.
int port = serverSocket.getLocalPort();
serverSocket.close();
return port;
}
private void startRegistration() {
manager.clearLocalServices(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.e(TAG, "onSuccess: Sucessss");
int port = 3030;
try {
port = findOpenSocket();
} catch (IOException e) {
e.printStackTrace();
}
Map record = new HashMap();
record.put("listenport", String.valueOf(port));
record.put("buddyname", iid);
record.put("available", "visible");
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance(serviceName, "_presence._tcp", record);
manager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "Local Service Added");
}
@Override
public void onFailure(int arg0) {
Log.d(TAG, "Failed to Add Local Service");
Log.e(TAG, String.valueOf(arg0));
}
});
}
@Override
public void onFailure(int arg0) {
Log.d(TAG, "P2P Unsupported");
}
});
}
private void discoverService() {
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
@Override
public void onDnsSdTxtRecordAvailable(
String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available - " + record.toString());
buddies.put(device.deviceAddress, (String) record.get("buddyname"));
}
};
WifiP2pManager.DnsSdServiceResponseListener servListener = new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType,
WifiP2pDevice resourceType) {
resourceType.deviceName = buddies
.containsKey(resourceType.deviceAddress) ? buddies
.get(resourceType.deviceAddress) : resourceType.deviceName;
String uId = instanceName.replace(baseServiceName + "_", "");
Log.d(TAG, "Received " + uId);
/*Discovered device1 = new Discovered();
device1.discoveredthreeID = uId;
Discovered.insertTransactionToSQLite(device1);*/
}
};
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel,
serviceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "Service Request Added");
}
@Override
public void onFailure(int code) {
Log.d(TAG, "Failed to Add Service Request");
}
});
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
manager.discoverServices(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "Discover Services Successful");
}
@Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else if (code == WifiP2pManager.ERROR) {
Log.d(TAG, "Error with P2P " + code);
} else if (code == WifiP2pManager.BUSY) {
Log.d(TAG, "P2P is Busy " + code);
}
}
});
}
}
大家好和我有同样的问题。我找到了解决方案。基本上,Android 10 (API 29) 将定位权限分离为普通定位权限和后台定位权限。您需要让您的应用程序提示后台权限(因为默认情况下不允许)。
将这些添加到您的 AndroidManifest.xml 文件
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
并且在我的 MainActivity onCreate 方法中我添加了一个检查以查看设备是否在 Android 10 (API 29) 上以及权限是否已被授予
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 1);
}
} else {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
如果其他人有更好的实现权限检查的方法,请在这里分享。我也想学谢谢!
我是新来的。无论如何,我一直在为这个问题挠头。我创建了一个 运行s WiFiP2pHelper 的服务来发现附近的设备并检索 WifiP2pDnsSdServiceInfo。我在多部手机上测试过,它们似乎都可以正常工作。如果它工作正常,它应该 return 记录如下:
2020-08-12 13:32:23.449 24345-24345/com.example.acts D/WiFi P2P Helper: Service Request Added
2020-08-12 13:32:23.449 24345-24345/com.example.acts D/WiFi P2P Helper: Discover Services Successful
2020-08-12 13:32:23.473 24345-24345/com.example.acts D/WiFi P2P Helper: Local Service Added
现在我在后台为 运行 提供服务(即使应用程序被终止)。它似乎在我测试过的设备上运行良好,除了 Android 10 上的任何 运行s。我怀疑是 Android 10 导致 WiFiP2pManager 或 WiFi P2P 本身不 运行 在后台。但我不完全确定它是否是 Android 10 引起的(我只有 2 Android 10 个设备进行了测试)。它 return 包含以下日志:
2020-08-12 13:33:23.517 24345-24345/com.example.acts D/WiFi P2P Helper: Service Request Added
2020-08-12 13:33:23.517 24345-24345/com.example.acts D/WiFi P2P Helper: Error with P2P 0
2020-08-12 13:33:23.518 24345-24345/com.example.acts D/WiFi P2P Helper: Failed to Add Local Service
2020-08-12 13:33:23.518 24345-24345/com.example.acts E/WiFi P2P Helper: 0
如您所见,“Error with P2P 0”和“Failed to Add Local Service”指向discoverServices和addLocalService。下面是代码。很抱歉把它全部转储在这里。任何帮助将不胜感激!谢谢!
public class WiFiP2PHelper extends Service {
WifiP2pManager manager;
WifiP2pManager.Channel channel;
WifiP2pDnsSdServiceRequest serviceRequest;
IntentFilter intentFilter;
String iid;
private String baseServiceName = "ACTS";
private String serviceName = "";
final HashMap<String, String> buddies = new HashMap<String, String>();
final String TAG = "WiFi P2P Helper";
Handler handler = new Handler();
Runnable runnable;
int delay = 15000;
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onCreate() {
super.onCreate();
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
getUser();
startRegistration();
discoverService();
startMyOwnForeground();
return START_STICKY;
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground() {
String NOTIFICATION_CHANNEL_ID = "com.example.acts";
String channelName = "My Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Hello World")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(1333, notification);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void getUser() {
List<User> users = User.getUser();
int count = users.size();
if (count > 0) {
User loggedInUser = users.get(0);
iid = loggedInUser.Id;
serviceName = baseServiceName + "_" + loggedInUser.Id;
Log.e("User", iid);
} else {
//uId = "User_Unregistered";
serviceName = baseServiceName + "_User_Unregistered";
Log.e("User in else", serviceName);
}
}
public String getWFDMacAddress() {
try {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface ntwInterface : interfaces) {
if (ntwInterface.getName().equalsIgnoreCase("p2p0")) {
byte[] byteMac = ntwInterface.getHardwareAddress();
if (byteMac == null) {
return null;
}
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < byteMac.length; i++) {
strBuilder.append(String.format("%02X:", byteMac[i]));
}
if (strBuilder.length() > 0) {
strBuilder.deleteCharAt(strBuilder.length() - 1);
}
return strBuilder.toString().toLowerCase();
}
}
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
public int findOpenSocket() throws IOException {
// Initialize a server socket on the next available port.
ServerSocket serverSocket = new ServerSocket(0);
// Store the chosen port.
int port = serverSocket.getLocalPort();
serverSocket.close();
return port;
}
private void startRegistration() {
manager.clearLocalServices(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.e(TAG, "onSuccess: Sucessss");
int port = 3030;
try {
port = findOpenSocket();
} catch (IOException e) {
e.printStackTrace();
}
Map record = new HashMap();
record.put("listenport", String.valueOf(port));
record.put("buddyname", iid);
record.put("available", "visible");
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance(serviceName, "_presence._tcp", record);
manager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "Local Service Added");
}
@Override
public void onFailure(int arg0) {
Log.d(TAG, "Failed to Add Local Service");
Log.e(TAG, String.valueOf(arg0));
}
});
}
@Override
public void onFailure(int arg0) {
Log.d(TAG, "P2P Unsupported");
}
});
}
private void discoverService() {
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
@Override
public void onDnsSdTxtRecordAvailable(
String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available - " + record.toString());
buddies.put(device.deviceAddress, (String) record.get("buddyname"));
}
};
WifiP2pManager.DnsSdServiceResponseListener servListener = new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType,
WifiP2pDevice resourceType) {
resourceType.deviceName = buddies
.containsKey(resourceType.deviceAddress) ? buddies
.get(resourceType.deviceAddress) : resourceType.deviceName;
String uId = instanceName.replace(baseServiceName + "_", "");
Log.d(TAG, "Received " + uId);
/*Discovered device1 = new Discovered();
device1.discoveredthreeID = uId;
Discovered.insertTransactionToSQLite(device1);*/
}
};
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel,
serviceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "Service Request Added");
}
@Override
public void onFailure(int code) {
Log.d(TAG, "Failed to Add Service Request");
}
});
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
manager.discoverServices(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "Discover Services Successful");
}
@Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else if (code == WifiP2pManager.ERROR) {
Log.d(TAG, "Error with P2P " + code);
} else if (code == WifiP2pManager.BUSY) {
Log.d(TAG, "P2P is Busy " + code);
}
}
});
}
}
大家好和我有同样的问题。我找到了解决方案。基本上,Android 10 (API 29) 将定位权限分离为普通定位权限和后台定位权限。您需要让您的应用程序提示后台权限(因为默认情况下不允许)。
将这些添加到您的 AndroidManifest.xml 文件
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
并且在我的 MainActivity onCreate 方法中我添加了一个检查以查看设备是否在 Android 10 (API 29) 上以及权限是否已被授予
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 1);
}
} else {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
如果其他人有更好的实现权限检查的方法,请在这里分享。我也想学谢谢!