我正在開發一個使用SimpleXpBeacon插件的科爾多瓦位置應用程序,並且我已經管理在ios的後臺運行我的應用程序,但是我無法運行應用程序在Android的背景。有人可以幫助我在後臺運行我的應用程序。這是由Cordova SimplexpPlugin提供的原生android代碼。 package com.blackberry.community;如何讓你的科爾多瓦android應用程序在後臺運行,而無需使用android服務
/*
* Copyright (c) 2015 BlackBerry Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.pm.PackageManager;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import java.lang.IllegalArgumentException;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class SimpleXpBeaconPlugin extends CordovaPlugin {
private static final String TAG = "SimpleXpBeaconPlugin";
private static final String PLUGIN_VERSION = "1.1.0";
private static final String ACTION_INITIALISE_BLUETOOTH = "initialiseBluetooth";
private static final String ACTION_TERMINATE_BLUETOOTH = "terminateBluetooth";
private static final String ACTION_PLUGIN_VERSION = "pluginVersion";
private static final String ACTION_START_MONITORING = "startMonitoring";
private static final String ACTION_STOP_MONITORING = "stopMonitoring";
private static final String ACTION_ADD_BEACON_UUID_TO_MONITOR = "addBeaconUuidToMonitor";
private static final String ACTION_REMOVE_BEACON_UUID_TO_MONITOR = "removeBeaconUuidToMonitor";
private static final String JSON_KEY_STATUS = "status";
private static final String JSON_KEY_DESCRIPTION = "desc";
private static final String JSON_KEY_ERROR_CODE = "error_code";
private static final String JSON_KEY_EVENT = "event";
private static final String JSON_KEY_PLUGIN_VERSION = "plugin_version";
private static final String JSON_KEY_DATA = "data";
private static final String JSON_KEY_IBEACON_UUID = "uuid";
private static final String JSON_KEY_IBEACON_MAJOR = "major";
private static final String JSON_KEY_IBEACON_MINOR = "minor";
private static final String JSON_KEY_IBEACON_RSSI = "rssi";
private static final String JSON_KEY_IBEACON_TXPOWER = "txpower";
private static final String JSON_VALUE_ERROR = "ERROR";
private static final String JSON_VALUE_OK = "OK";
private static final String JSON_VALUE_STARTED = "STARTED";
private static final String JSON_VALUE_IBEACON = "IBEACON";
private static final String JSON_VALUE_PLUGIN_DESCRIPTION = "Plugin Version";
private static final String JSON_VALUE_NO_BT_LE_FEATURE = "This device doesn't have BT LE feature";
private static final String JSON_VALUE_NO_BT_ADAPTER = "Unable to obtain Bluetooth Adapter";
private static final String JSON_VALUE_BT_ALREADY_INITIALISED = "Bluetooth already initialised";
private static final String JSON_VALUE_BT_NOT_INITIALISED = "Bluetooth not initialised";
private static final String JSON_VALUE_BT_INITIALISED = "Bluetooth initialised";
private static final String JSON_VALUE_BT_TERMINATE = "Bluetooth Terminated";
private static final int JSON_VALUE_DEFAULT_ERROR_CODE = -1;
private static final String JSON_VALUE_ALREADY_MONITORING_FOR_I_BEACONS = "Already monitoring for iBeacons";
private static final String JSON_VALUE_FAILED_TO_ENABLE_MONITORING = "Failed to enable iBeacon monitoring";
private static final String JSON_VALUE_NOT_MONITORING = "Not monitoring for iBeacons";
private static final String JSON_VALUE_FAILED_TO_DISABLE_MONITORING = "Failed to Disable Monitoring";
private static final String JSON_VALUE_STOPPED_MONITORING = "Stopped Monitoring for iBeacons OK";
private static final String JSON_VALUE_REQUESTED_MONITORING = "Requested iBeacon Monitoring OK";
private static final String JSON_VALUE_IBEACON_EVENT = "iBeacon event";
private static final String JSON_VALUE_UUID_WAS_IMPROPER_FORMAT = "UUID was improper format";
private static final String JSON_VALUE_UUID_WAS_NULL = "UUID was null";
private static final String JSON_VALUE_UUID_ADDED = "UUID added";
private static final String JSON_VALUE_IBEACON_ALREADY_BEING_MONITORED = "iBeacon already being monitored";
private static final String JSON_VALUE_BEACON_REMOVED = "iBeacon UUID removed successfully";
private static final String JSON_VALUE_NO_MATCH_TO_BEACON_UUID = "iBeacon UUID did not match any being monitored";
private BluetoothAdapter mBluetoothAdapter;
private boolean mBtInitialised = false;
private boolean mMonitoring = false;
private CallbackContext mMonitoringCallbackContext;
private List<UUID> mBeaconRegionsToMonitor;
private boolean mSupressMonitorCallback = false;
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Device Address: " + device.getAddress().toString());
Log.d(TAG, "RSSI: " + rssi);
BeaconData beaconData = new BeaconData(scanRecord);
if (beaconData.hasIBeaconData()) {
boolean isEmpty = true;
boolean containsUuid = true;
synchronized(SimpleXpBeaconPlugin.this) {
isEmpty = mBeaconRegionsToMonitor.isEmpty();
containsUuid = mBeaconRegionsToMonitor.contains(beaconData.uuid());
}
if (!isEmpty && !containsUuid) {
Log.d(TAG, "Skipping notification of UUID: " + beaconData.uuid().toString());
return;
}
Log.d(TAG, "TxPowerLevel: " + beaconData.txPowerLevel());
Log.d(TAG, "Major: " + beaconData.major());
Log.d(TAG, "Minor: " + beaconData.minor());
Log.d(TAG, "UUID: " + beaconData.uuid().toString());
JSONObject response = new JSONObject();
JSONObject data = new JSONObject();
try {
data.put(JSON_KEY_IBEACON_UUID, beaconData.uuid().toString());
data.put(JSON_KEY_IBEACON_MAJOR, beaconData.major());
data.put(JSON_KEY_IBEACON_MINOR, beaconData.minor());
data.put(JSON_KEY_IBEACON_RSSI, rssi);
data.put(JSON_KEY_IBEACON_TXPOWER, beaconData.txPowerLevel());
response.put(JSON_KEY_STATUS, JSON_VALUE_OK);
response.put(JSON_KEY_EVENT, JSON_VALUE_IBEACON);
response.put(JSON_KEY_DESCRIPTION, JSON_VALUE_IBEACON_EVENT);
response.put(JSON_KEY_DATA, data);
if (!isSupressMonitorCallback()) {
PluginResult result = new PluginResult(PluginResult.Status.OK, response.toString());
result.setKeepCallback(true);
getMonitoringCallbackContext().sendPluginResult(result);
}
} catch (JSONException e) {
Log.d(TAG, "JSON Error: " + e.getMessage());
}
}
}
});
}
};
@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
LOG.d(TAG, "in initialize");
mBeaconRegionsToMonitor = new ArrayList<UUID>();
}
@Override
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
LOG.d(TAG, "requested action = " + action);
boolean validAction = false;
if (action.equals(ACTION_INITIALISE_BLUETOOTH)) {
LOG.d(TAG, "Processing Initialise Bluetooth request");
validAction = true;
if (!deviceHasBtLeFeature()) {
errorResponse(callbackContext, JSON_VALUE_NO_BT_LE_FEATURE);
return validAction;
}
if (isBtInitialised()) {
errorResponse(callbackContext, JSON_VALUE_BT_ALREADY_INITIALISED);
return validAction;
}
BluetoothManager bluetoothManager =
(BluetoothManager) cordova.getActivity()
.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
errorResponse(callbackContext, JSON_VALUE_NO_BT_ADAPTER);
return validAction;
}
successResponse(callbackContext, JSON_VALUE_BT_INITIALISED);
setBtInitialised(true);
return validAction;
} else if (action.equals(ACTION_TERMINATE_BLUETOOTH)) {
LOG.d(TAG, "Processing Terminate Bluetooth request");
validAction = true;
if (!isBtInitialised()) {
errorResponse(callbackContext, JSON_VALUE_BT_NOT_INITIALISED);
return validAction;
}
mBluetoothAdapter.disable();
mBluetoothAdapter = null;
successResponse(callbackContext, JSON_VALUE_BT_TERMINATE);
setBtInitialised(false);
return validAction;
} else if (action.equals(ACTION_PLUGIN_VERSION)) {
LOG.d(TAG, "Processing Plugin Version request");
validAction = true;
pluginVersionResponse(callbackContext, PLUGIN_VERSION);
return validAction;
} else if (action.equals(ACTION_START_MONITORING)) {
LOG.d(TAG, "Processing Start Monitoring request");
validAction = true;
if (!isBtInitialised()) {
errorResponse(callbackContext, JSON_VALUE_BT_NOT_INITIALISED);
return validAction;
}
if (isMonitoring()) {
errorResponse(callbackContext, JSON_VALUE_ALREADY_MONITORING_FOR_I_BEACONS);
return validAction;
}
if (!enableMonitoring(callbackContext)) {
monitorFailResponse(callbackContext);
return validAction;
}
setSupressMonitorCallback(false);
monitorSuccessResponse(callbackContext);
return validAction;
} else if (action.equals(ACTION_STOP_MONITORING)) {
LOG.d(TAG, "Processing Stop Monitoring request");
validAction = true;
if (!isBtInitialised()) {
errorResponse(callbackContext, JSON_VALUE_BT_NOT_INITIALISED);
return validAction;
}
if (!isMonitoring()) {
errorResponse(callbackContext, JSON_VALUE_NOT_MONITORING);
return validAction;
}
if (!disableMonitoring(callbackContext)) {
errorResponse(callbackContext, JSON_VALUE_FAILED_TO_DISABLE_MONITORING);
return validAction;
}
successResponse(callbackContext, JSON_VALUE_STOPPED_MONITORING);
return validAction;
} else if (action.equals(ACTION_ADD_BEACON_UUID_TO_MONITOR)) {
LOG.d(TAG, "Processing Add Beacon to Monitor request");
validAction = true;
UUID beaconRegionUuid;
try {
beaconRegionUuid = UUID.fromString(args.getString(0));
if (!mBeaconRegionsToMonitor.contains(beaconRegionUuid)) {
synchronized(SimpleXpBeaconPlugin.this) {
mBeaconRegionsToMonitor.add(beaconRegionUuid);
}
successResponse(callbackContext, JSON_VALUE_UUID_ADDED);
} else {
errorResponse(callbackContext, JSON_VALUE_IBEACON_ALREADY_BEING_MONITORED);
}
} catch (NullPointerException e) {
LOG.d(TAG, "" + JSON_VALUE_UUID_WAS_NULL);
errorResponse(callbackContext, JSON_VALUE_UUID_WAS_NULL);
} catch (IllegalArgumentException e) {
LOG.d(TAG, "" + JSON_VALUE_UUID_WAS_IMPROPER_FORMAT);
errorResponse(callbackContext, JSON_VALUE_UUID_WAS_IMPROPER_FORMAT);
}
return validAction;
} else if (action.equals(ACTION_REMOVE_BEACON_UUID_TO_MONITOR)) {
LOG.d(TAG, "Processing Remove Beacon to Monitor request");
validAction = true;
UUID beaconRegionUuid;
boolean removed = false;
try {
beaconRegionUuid = UUID.fromString(args.getString(0));
synchronized(SimpleXpBeaconPlugin.this) {;
removed = mBeaconRegionsToMonitor.remove(beaconRegionUuid);
}
if (removed) {
successResponse(callbackContext, JSON_VALUE_BEACON_REMOVED);
} else {
errorResponse(callbackContext, JSON_VALUE_NO_MATCH_TO_BEACON_UUID);
}
} catch (NullPointerException e) {
LOG.d(TAG, "" + JSON_VALUE_UUID_WAS_NULL);
errorResponse(callbackContext, JSON_VALUE_UUID_WAS_NULL);
} catch (IllegalArgumentException e) {
LOG.d(TAG, "" + JSON_VALUE_UUID_WAS_IMPROPER_FORMAT);
errorResponse(callbackContext, JSON_VALUE_UUID_WAS_IMPROPER_FORMAT);
}
return validAction;
} else {
LOG.d(TAG, "Unmatched action" + action);
validAction = false;
}
return validAction;
}
private boolean enableMonitoring(CallbackContext callbackContext) {
boolean rc = true;
if (mBluetoothAdapter.startLeScan(mLeScanCallback)) {
setMonitoring(true);
setMonitoringCallbackContext(callbackContext);
} else {
setMonitoring(false);
rc = false;
}
return rc;
}
private boolean disableMonitoring(CallbackContext callbackContext) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
setMonitoring(false);
setMonitoringCallbackContext(null);
return true;
}
private void pauseMonitoring() {
if (isMonitoring()) {
setSupressMonitorCallback(true);
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private void resumeMonitoring() {
if (isMonitoring()) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
setSupressMonitorCallback(false);
}
}
private void pluginVersionResponse(CallbackContext callbackContext, String version) throws JSONException {
// {"desc":"Plugin Version","plugin_version":"1.0.0","status":"OK"}
JSONObject response = new JSONObject();
response.put(JSON_KEY_PLUGIN_VERSION, version);
response.put(JSON_KEY_DESCRIPTION, JSON_VALUE_PLUGIN_DESCRIPTION);
response.put(JSON_KEY_STATUS, JSON_VALUE_OK);
callbackContext.success(response.toString());
}
private void successResponse(CallbackContext callbackContext, String description) throws JSONException {
// {"desc":"...","status":"OK"}
JSONObject response = new JSONObject();
response.put(JSON_KEY_DESCRIPTION, description);
response.put(JSON_KEY_STATUS, JSON_VALUE_OK);
callbackContext.success(response.toString());
}
private void monitorSuccessResponse(CallbackContext callbackContext) throws JSONException {
// {"desc":"...","status":"OK"}
JSONObject response = new JSONObject();
response.put(JSON_KEY_DESCRIPTION, JSON_VALUE_REQUESTED_MONITORING);
response.put(JSON_KEY_STATUS, JSON_VALUE_OK);
response.put(JSON_KEY_EVENT, JSON_VALUE_STARTED);
PluginResult result = new PluginResult(PluginResult.Status.OK, response.toString());
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
private void monitorFailResponse(CallbackContext callbackContext) throws JSONException {
// {"desc":"...","status":"ERROR", "error_code": nnn, "event":"STARTED"}
JSONObject response = new JSONObject();
response.put(JSON_KEY_DESCRIPTION, JSON_VALUE_FAILED_TO_ENABLE_MONITORING);
response.put(JSON_KEY_STATUS, JSON_VALUE_ERROR);
response.put(JSON_KEY_ERROR_CODE, JSON_VALUE_DEFAULT_ERROR_CODE);
response.put(JSON_KEY_EVENT, JSON_VALUE_STARTED);
callbackContext.success(response.toString());
}
private void errorResponse(CallbackContext callbackContext, String description) throws JSONException {
// {"desc":"...","status":"ERROR", "error_code": nnn}
JSONObject response = new JSONObject();
response.put(JSON_KEY_DESCRIPTION, description);
response.put(JSON_KEY_STATUS, JSON_VALUE_ERROR);
response.put(JSON_KEY_ERROR_CODE, JSON_VALUE_DEFAULT_ERROR_CODE);
callbackContext.success(response.toString());
}
@Override
public void onDestroy() {
super.onDestroy();
LOG.d(TAG, "In onDestroy()");
if (isMonitoring()) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
setMonitoring(false);
}
if (mBluetoothAdapter != null) {
mBluetoothAdapter = null;
setBtInitialised(false);
}
}
@Override
public void onPause(boolean multitasking) {
super.onPause(multitasking);
LOG.d(TAG, "In onPause()");
pauseMonitoring();
}
@Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
LOG.d(TAG, "In onResume()");
resumeMonitoring();
}
private boolean deviceHasBtLeFeature() {
boolean rc = false;
if (cordova.getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
rc = true;
}
return rc;
}
public boolean isSupressMonitorCallback() {
return mSupressMonitorCallback;
}
public void setSupressMonitorCallback(boolean supressMonitorCallback) {
this.mSupressMonitorCallback = supressMonitorCallback;
}
private boolean isBtInitialised() {
return mBtInitialised;
}
private void setBtInitialised(boolean btInitialised) {
this.mBtInitialised = btInitialised;
}
private boolean isMonitoring() {
return mMonitoring;
}
private void setMonitoring(boolean monitoring) {
this.mMonitoring = monitoring;
}
private CallbackContext getMonitoringCallbackContext() {
return mMonitoringCallbackContext;
}
private void setMonitoringCallbackContext(CallbackContext monitoringCallbackContext) {
this.mMonitoringCallbackContext = monitoringCallbackContext;
}
private class BeaconData {
private byte[] mScanData;
private int mMajor = 0;
private int mMinor = 0;
private int mTxPowerLevel = 0;
private UUID mUuid;
private boolean mHasIBeaconData = false;
public BeaconData(byte[] scanData) {
this.mScanData = scanData.clone();
parseScanData();
}
private void parseScanData() {
mHasIBeaconData = false;
if (mScanData.length < 27) {
return;
}
byte[] beaconUuid = new byte[16];
byte[] beaconUuidLowHalf = new byte[beaconUuid.length/2];
byte[] beaconUuidHighHalf = new byte[beaconUuid.length/2];
long beaconUuidLeastSig = 0;
long beaconUuidMostSig = 0;
int i = 0;
int entryLen = 0;
int entryType = 0;
do {
entryLen = mScanData[i];
entryType = mScanData[i+1];
if ((entryType & 0xff) == 0xff) {
int j = i+2;
if ((mScanData[j] == 0x4c) && (mScanData[j+1] == 0x00) &&
(mScanData[j+2] == 0x02) && (mScanData[j+3] == 0x15)) {
mHasIBeaconData = true;
for (int k=0; k<beaconUuid.length; k++) {
beaconUuid[k] = mScanData[k+j+4];
}
j += (beaconUuid.length + 4);
mMajor = 0;
mMajor = (mScanData[j+1] & 0xff);
mMajor += ((mScanData[j] & 0xff) << 8);
j += 2;
mMinor = 0;
mMinor = (mScanData[j+1] & 0xff);
mMinor += ((mScanData[j] & 0xff) << 8);
j += 2;
mTxPowerLevel = ((-1 << 8) & 0xffffff00);
mTxPowerLevel += (mScanData[j] & 0xff);
}
}
i += (entryLen+1);
} while (i < mScanData.length && entryLen != 0);
if (mHasIBeaconData) {
for (i=0; i < (beaconUuidLowHalf.length); i++) {
beaconUuidHighHalf[i] = beaconUuid[i];
beaconUuidLowHalf[i] = beaconUuid[i + beaconUuidLowHalf.length];
}
beaconUuidLeastSig = bytesToLong(beaconUuidLowHalf);
beaconUuidMostSig = bytesToLong(beaconUuidHighHalf);
mUuid = new UUID(beaconUuidMostSig, beaconUuidLeastSig);
}
}
private long bytesToLong(byte[] b) {
long result = 0;
for (int i = 0; i < 8; i++) {
result <<= 8;
result |= (b[i] & 0xFF);
}
return result;
}
public boolean hasIBeaconData() {
return mHasIBeaconData;
}
public int txPowerLevel() {
return mTxPowerLevel;
}
public int major() {
return mMajor;
}
public int minor() {
return mMinor;
}
public UUID uuid() {
return mUuid;
}
}
}
Do I need to use the android service to run my application in background?