Flutter: Firebase messaging with patform channels - Duplicated FlutterActivity - android

I'm trying to implement an app using Flutter. The app should be able to send messages from the smartphones to a server using FCM or receive messages from the server via FCM.
I implemented the FCM functionality using the firebase_messaging plugin (https://pub.dev/packages/firebase_messaging). Everything is working fine for downstream messages (server -> device). Now I tried to add upstream messages (device -> server). As far as I know from the docs, the plugin does not support upstream messages yet. So I began to write native code to send the messages to the server and call this code via platform channel functionality (https://flutter.dev/docs/development/platform-integration/platform-channels?tab=android-channel-kotlin-tab).
Initial MainActivity.kt:
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
}
}
Added the method channel example from Flutter docs. Using the imports specified in the Flutter docs:
private val CHANNEL = "samples.flutter.dev/battery"
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
// Note: this method is invoked on the main thread.
call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
}
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
But unfortunately there occurs a problem. The firebase_messaging plugin requires the mainactivity.kt to extend io.flutter.app.FlutterActivity. Platform channels require the mainactivity.kt to extend io.flutter.embedding.android.FlutterActivity.
Is there any way to use both - firebase_messaging plugin and method channels?

I compared my code to the example project from the firebase_messaging plugin: https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_messaging/example/android/app/src/main/java/io/flutter/plugins/firebasemessagingexample/MainActivity.java
Then I realized that the example uses the io.flutter.embedding.android.FlutterActivity too. After changing the import statements to the io.flutter.embedding... package I removed the GeneratedPluginRegistrant.registerWith(this) as GeneratedPluginRegistrant is an import from io.flutter.plugins.GeneratedPluginRegistrant and does not seem to match the embedding package. Then I checked the fields and functions in io.flutter.embedding.engine.FlutterEngine again and added following line: flutterEngine?.plugins?.add(FirebaseMessagingPlugin())
After this I recompiled the app and at the start it prints out the FCM device ID and the battery status successfully.
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Bundle
import androidx.annotation.NonNull
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin
class MainActivity : io.flutter.embedding.android.FlutterActivity() {
private val CHANNEL = "samples.flutter.dev/battery"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
flutterEngine?.plugins?.add(FirebaseMessagingPlugin())
}
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
// Note: this method is invoked on the main thread.
call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
}
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
}

Related

Display notification if the battery becomes less than 10% in Android by Kotlin

How can I display a notification if the battery becomes less than 10% in an Android studio by Kotlin using a broadcast receiver?
Create a new Android project with this in the
Add the AndroidX support library to your module's build.gradle (where the other implementations are:
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
}
MainActivity.kt Imports:
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
import kotlin.concurrent.thread
MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
thread {
val mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val mChannel = NotificationChannel("default", "default", NotificationManager.IMPORTANCE_DEFAULT)
mNotificationManager.createNotificationChannel(mChannel)
while (true) {
val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
this.registerReceiver(null, ifilter)
}
val batteryPct: Float = batteryStatus?.let { intent ->
val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
level * 100 / scale.toFloat()
} ?: 100f
if (batteryPct <= 10) {
val notif = NotificationCompat.Builder(this, "default").setContentText("Low Battery: ${batteryPct.toInt()}%").setSmallIcon(R.drawable.ic_launcher_foreground).build()
mNotificationManager.notify(1, notif) // re-use notification in tray
}
Thread.sleep(20000) // check every 20 seconds
}
}
}
}
Add permission in manifest. Register your broadcast receiver. Read more in this tutorial
https://developer.android.com/training/monitoring-device-state/battery-monitoring

How to Connect native android / Kotlin functionality to react native?

I have implemented SMSBroadcast Receiver functionality in native android (Kotlin) code.
The functionality is like whenever a new text message (SMS) is received I need to call an api (even the app is in background).
When i run as standalone android application its working fine. But how to integrate this with my react-native app?
The below is the code i wrote natively.
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.telephony.SmsMessage
import android.util.Log
import android.widget.Toast
import com.reactnativecommunity.asyncstorage.AsyncLocalStorageUtil
import com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier
class SMSBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.i(
TAG,
"Intent received: " + intent.action
)
if (intent.action === SMS_RECEIVED) {
val bundle = intent.extras
var data = ""
if (bundle != null) {
val pdus =
bundle["pdus"] as Array<Any>?
val messages =
arrayOfNulls<SmsMessage>(pdus!!.size)
for (i in pdus.indices) {
messages[i] =
SmsMessage.createFromPdu(pdus[i] as ByteArray)
}
if (messages.size > -1) {
data = messages[0]!!.messageBody
Log.i(
TAG,
"Message recieved: $data"
)
}
}
Toast.makeText(context,"Message received : $data", Toast.LENGTH_LONG).show()
// var accessToken = AsyncLocalStorageUtil.getItemImpl(ReactDatabaseSupplier.getInstance(context).get(), "");
// if (accessToken != null){
//
// }
if(listener!= null)
{
listener?.onSmsReceive(data)
}
}
}
companion object {
private const val SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED"
private const val TAG = "SMSBroadcastReceiver"
var listener : OnCustomSmsListener ?= null
}
}
** Package suggestions are also welcome **

Coroutines Broadcast Channel/Receive channel eventbus skips first elemet

This is the eventbus implementation using Broadcast channel. (RxJava2 not allowed :( )
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.*
import kotlin.coroutines.CoroutineContext
class EventBus(override val coroutineContext: CoroutineContext
= Dispatchers.Default) :CoroutineScope {
#ExperimentalCoroutinesApi
private val channel = BroadcastChannel<Any>(1)
#ExperimentalCoroutinesApi
suspend fun send(event: Any) {
channel.send(event)
}
#ExperimentalCoroutinesApi
fun subscribe(): ReceiveChannel<Any> =
channel.openSubscription()
#ExperimentalCoroutinesApi
inline fun <reified T> subscribeToEvent() =
subscribe().let {
produce<T>(coroutineContext) {
for (t in it){
if(t is T)
send(t as T)
}
}
}
}
And here is my testing code.
#Test
fun testEventBus(){
val bus = EventBus()
var i = 1;
var isFinish = false
CoroutineScope(Dispatchers.IO).launch{
println("launching_subsc")
bus.subscribe().consumeEach {
println("received $it")
assert(it == i++)
isFinish = (it == 5)
}
withContext(bus.coroutineContext){
}
}
bus.launch {
delay(500)
for (j in 1..5) {
println("sending $j")
bus.send(j)
sleep(500)
}
}
while (!isFinish)
sleep(50)
}
This test works good, but I want to remove the delay(500) and yet expect the test to work.
If I remove the delay(500) now, the output is
launching_subsc
sending 1
sending 2
received 2
...
or
sending 1
launching_subsc
sending 2
received 2
...
My actual need is that in actual project scenario I want the data to be published after the subscription, again, if there is no subscriber, the events need to be dropped.
So if there is a subscription call before publishing call(irrespective of Dispatchers) the subscriber must receive all the events.
I have tried using the same scope/dispatcher, nothing is working.

FlutterActivity MethodChannel and FlutterView

So I wrote a Flutter App about 4 Months ago. Now I wanted to do a small change, but I can't compile the app anymore, because GeneratedPluginRegistrant.registerWith(this) doesn't work anymore, I didn't change the Kotlin code only the Dart code.
The "this" in "GeneratedPluginRegistrant.registerWith(this)" shows me this error:
Type mismatch.
Required: FlutterEngine!
Found: MainActivity
The MainActivity Class:
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.view.FlutterMain
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this) // here is the error: Type mismatch. Required: FlutterEngine! Found: MainActivity
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "helloFromNativeCode") {
val greetings = helloFromNativeCode()
result.success(greetings)
}
}
}
private fun helloFromNativeCode(): String {
return "Hello from Native Android Code"
}
companion object {
private const val CHANNEL = "flutter.native/helper"
}
}
And if is use:
import io.flutter.embedding.android.FlutterActivity
instead of
import io.flutter.app.FlutterActivity
I can use
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
but have trouble with:
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "helloFromNativeCode") {
val greetings = helloFromNativeCode()
result.success(greetings)
}
}
because i get an error on flutterView:
Unresolved reference: flutterView
The code would look like this:
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.view.FlutterMain
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result -> // here is the error
if (call.method == "helloFromNativeCode") {
val greetings = helloFromNativeCode()
result.success(greetings)
}
}
}
private fun helloFromNativeCode(): String {
return "Hello from Native Android Code"
}
companion object {
private const val CHANNEL = "flutter.native/helper"
}
}
I hope someone can help me.
Instead of flutterView use flutterEngine.getDartExecutor().
I spent days trying to figure out how to add a Flutter UI to my existing Android App. The biggest challenge was getting the MethodChannel to work with FlutterActivity being called from MainActivity. I know this is a little different than the question asked here, but this post was returned when I did searches for 'Android FlutterActivity MethodChannel'. After going through many resources on how to do this, I finally found my solution here:
https://github.com/flutter/samples/tree/master/add_to_app/android_using_plugin/app/src/main/java/dev/flutter/example/androidusingplugin
Initially, in Android Studio, with the existing app opened, I tapped File, New, New Module, Flutter Module. I received an error and had to perform manual steps.
My objective is to launch FlutterActivity (opens main.dart in the flutter_module) in MainActivity - onCreate, then develop Flutter 'screens' leveraging as much native Flutter code as possible, with limited Platform calls using the MethodChannel. As I develop replacement Flutter code, I will continue to comment on the existing Android Code.
Here is what finally worked for me:
../App_Project/Android/Existing_Android_App/settings.gradle
include ':app'
setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir.parentFile, '../flutter_module/.android/include_flutter.groovy'))
include ':flutter_module’
project(':flutter_module’).projectDir = new File('../../flutter_module’)
rootProject.name=‘existing_android_app’
../App_Project/Android/Existing_Android_App/app/build.gradle
dependencies {
…
implementation project(':flutter')
}
../App_Project/Android/Existing_Android_App/app/src/main/AndroidManifest.xml
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" />
../App_Project/Android/Existing_Android_App/app/src/main/java/com/existing_android_app/MainActivity.java
package com.existing_android_app;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends AppCompatActivity {
final String ENGINE_ID = "1";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FlutterEngine flutterEngine = new FlutterEngine(this);
flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine);
MethodChannel channel = new MethodChannel(flutterEngine.getDartExecutor(), "com.existing_android_app/myMethodChannel");
channel.setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
#Override
public void onMethodCall(#NonNull MethodCall call, #NonNull MethodChannel.Result result) {
String url = call.argument("url");
if (call.method.equals("openBrowser")) {
openBrowser(url);
}
else {
result.notImplemented();
}
}
});
startActivity(FlutterActivity.withCachedEngine(ENGINE_ID).build(this));
}
void openBrowser(String url) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
this.startActivity(intent);
}
}
../App_Project/flutter_module/lib/home_page.dart
class AppHomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<AppHomePage> {
static const platform = const MethodChannel(‘com.existing_android_app/myMethodChannel’);
Future<void> _openBrowser() async {
try {
final int result = await platform.invokeMethod('openBrowser', <String, String> { 'url': "http://bing.com" });
}
catch (e) {
print('***** _openBrowser error: ' + e.toString());
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: CustomAppBar(),
body: Column(
children: <Widget>[
RaisedButton(
label: Text('Search',
style: TextStyle(fontSize: 18.0),
),
onPressed: () { _openBrowser(); },
) // RaisedButton.icon
], // Widget
) // Column
) // Scaffold
); // SafeArea
}
You should use
import io.flutter.embedding.android.FlutterActivity;
and declare your patformChannel in
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
// Note: this method is invoked on the main thread.
// TODO
}
);
}
for more you can check the documentation: https://flutter.dev/docs/development/platform-integration/platform-channels
You can use method channel and flutter engine like this.
private val CHANNEL = "adb"
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler { call, result ->
//You can use your custom function for example:
if (call.method.equals("checkingadb")) {
checkingadb(call, result)
} else {
result.notImplemented()
}
}
}
private fun checkingadb(call: MethodCall, result: MethodChannel.Result) {
if (Settings.Secure.getInt(this.getContentResolver(), Settings.Secure.ADB_ENABLED, 0) === 1) {
// debugging enabled
result.success(1)
} else {
// debugging is not enabled
result.success(0)
}
}
To pass flutter Engine value we can use provideFlutterEngine(this) method. And for flutterView we can use flutterEngine.dartExecutor. Here is the url for code snippet ,have answered it earlier
https://stackoverflow.com/a/67698834/11887774 .

RxAndroidBLE do not find devices on android 4.3

Hello I'm using RxAndroidBLE to detect a BLE device. On android 6 >= everything seems to work okay but not on a 4.3 device.
My app can only discover the desirable BLE device only once at start. After the device has been discovered no more new discoveries at all until I restart the app. Any advice would be highly appreciated.
Below minimum (not)working code example:
MainActivity
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import com.polidea.rxandroidble.RxBleClient
import com.polidea.rxandroidble.exceptions.BleScanException
import com.polidea.rxandroidble.scan.ScanResult
import com.polidea.rxandroidble.scan.ScanSettings
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startLeScan(applicationContext)
}
private var rxBleClient: RxBleClient? = null
private var scanSubscription: Subscription? = null
private var handler: Handler? = null
private var timer: Timer? = null
private var timerTask: TimerTask? = null
private var delay: Int = 0
private fun isScanning(): Boolean {
return scanSubscription != null
}
fun startLeScan(context: Context) {
rxBleClient = MyaPP.getRxBleClient(context)
if (isScanning()) {
scanSubscription?.unsubscribe()
} else {
scanSubscription = rxBleClient?.scanBleDevices(
com.polidea.rxandroidble.scan.ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build())
?.observeOn(AndroidSchedulers.mainThread())
//?.doOnNext(this::newDevicesFound)
?.doOnUnsubscribe(this::clearSubscription)
?.subscribe(this::newDevicesFound, this::onScanFailure)
}
if(handler == null) {
handler = Handler()
timer = Timer(false)
timerTask = object : TimerTask() {
override fun run() {
handler?.post {
if (delay > 7) {
delay = 0
val service = Executors.newSingleThreadExecutor()
service.submit(Runnable {
//startLeScan(context)
})
} else {
delay = delay + 1
}
}
}
}
timer?.scheduleAtFixedRate(timerTask, 0, 300)
}
}
private fun newDevicesFound(devices: ScanResult) {
Log.d("WHYY??", devices.bleDevice.name)
}
fun stopScan() {
scanSubscription?.unsubscribe()
destroy()
}
private fun clearSubscription() {
scanSubscription = null
}
private fun onScanFailure(throwable: Throwable) {
if (throwable is BleScanException) {
handleBleScanException(throwable)
}
}
private fun handleBleScanException(bleScanException: BleScanException) {
val text: String
when (bleScanException.reason) {
BleScanException.BLUETOOTH_NOT_AVAILABLE -> text = "Bluetooth is not available"
BleScanException.BLUETOOTH_DISABLED -> text = "Enable bluetooth and try again"
BleScanException.LOCATION_PERMISSION_MISSING -> text = "On Android 6.0 location permission is required. Implement Runtime Permissions"
BleScanException.LOCATION_SERVICES_DISABLED -> text = "Location services needs to be enabled on Android 6.0"
BleScanException.SCAN_FAILED_ALREADY_STARTED -> text = "Scan with the same filters is already started"
BleScanException.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> text = "Failed to register application for bluetooth scan"
BleScanException.SCAN_FAILED_FEATURE_UNSUPPORTED -> text = "Scan with specified parameters is not supported"
BleScanException.SCAN_FAILED_INTERNAL_ERROR -> text = "Scan failed due to internal error"
BleScanException.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES -> text = "Scan cannot start due to limited hardware resources"
BleScanException.UNDOCUMENTED_SCAN_THROTTLE -> text = String.format(
Locale.getDefault(),
"Android 7+ does not allow more scans. Try in %d seconds",
secondsTill(bleScanException.retryDateSuggestion)
)
BleScanException.UNKNOWN_ERROR_CODE, BleScanException.BLUETOOTH_CANNOT_START -> text = "Unable to start scanning"
else -> text = "Unable to start scanning"
}
Log.w("EXCEPTION", text, bleScanException)
}
private fun secondsTill(retryDateSuggestion: Date?): Long {
if (retryDateSuggestion != null) {
return TimeUnit.MILLISECONDS.toSeconds(retryDateSuggestion.time - System.currentTimeMillis())
}
return 0
}
private fun destroy() {
timer?.cancel()
handler?.removeCallbacks(timerTask)
handler = null
timerTask = null
timer = null
}
}
MyaPP
import android.app.Application
import android.content.Context
import com.polidea.rxandroidble.RxBleClient
import com.polidea.rxandroidble.internal.RxBleLog
class MyaPP: Application() {
private var rxBleClient: RxBleClient? = null
companion object {
fun getRxBleClient(context: Context): RxBleClient? {
val application = context.applicationContext as MyaPP
return application.rxBleClient
}
}
override fun onCreate() {
super.onCreate()
rxBleClient = RxBleClient.create(this)
RxBleClient.setLogLevel(RxBleLog.DEBUG)
}
}
build.gradle
compile "com.polidea.rxandroidble:rxandroidble:1.5.0"
implementation 'io.reactivex:rxandroid:1.2.1'
manifest
<application
android:name=".MyaPP"
Your code looks a lot like the library's sample app (version 1.5.0, branch master-rxjava1). I have checked that recently on Android 4.4.4 which is the oldest I have and it worked fine. There were no API changes between 4.3 and 4.4.
What you may be experiencing is a behaviour specific to your device (feel free to share your phone model) in which it only callbacks for the first time it scans a particular peripheral. There are some threads about this topic already like this one.

Categories

Resources