I am working on the functionality to fetch logs of application and upload it to server. We are writing logs into file.
What i need to do?
We have used fabric(Currently Firebase crashlystics) for crash reporting. but some time lots of crashes are missed out. so we are unable to track client issue. We decided to implement our own crash reporting tool. We decided to upload logs while starting of the application without any further process. Once app crash then crash report will be write to the file and while app launch next time, that file will be uploaded to server. I don't want to stuck user for such things so i have decided to do this with services. so i need to start service when app is starting and logs should be uploaded to server within service without any hardles. If app crash after next line of the service start, the service should not stop
What i have tried ?
I have used service to upload logs to server. I have tried to start foreground service on application class onCreate()
the service will be on different process and that is working fine as expected. but problem is that, If any crash happen on login activity (first activity) onCreate()
the foreground service is not starting as expected. Service process is stopped after crash.
What i want ?
I want to start foreground service or intent service which upload logs to server. and after uploading logs it will stop. Meanwhile if app crash for some other reason service should not stop and it should complete their task.
Code
Application class
public void onCreate() {
startLogService()
// Other code
}
private void startLogService() {
Intent serviceIntent = new Intent(this, LogWriteService.class);
/* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // i have tried with this also
startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}*/
bindService(serviceIntent, m_serviceConnection, BIND_AUTO_CREATE);
}
LogInActivity
public class LoginActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_initial_login);
int i = 10/0; // just for crash test
}
}
LogSendService class (Intent service)
class LogSendService : IntentService("LogSendService") {
private val NOTIFICATION_ID = 12345
internal var allLogFile: File? = null
override fun onHandleIntent(intent: Intent?) {
createAndShowForegroundNotification(this, NOTIFICATION_ID, "We are gathering logs", true)
writeLogs()
}
private fun createAndShowForegroundNotification(mService: Service, notificationId: Int, message: String, isOnGoing: Boolean) {
val builder = getNotificationBuilder(mService,
"Log Service", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW) //Low importance prevent visual appearance for this notification channel on top
builder.setSmallIcon(R.mipmap.home_icon)
.setContentTitle(mService.getString(R.string.app_name))
.setContentText(message)
if (isOnGoing) {
builder.setOngoing(true)
}
val notification = builder.build()
mService.startForeground(notificationId, notification)
}
private fun writeLogs() {
try {
//log write and upload process
createAndShowForegroundNotification(this, NOTIFICATION_ID, "success", false)
} catch (e: Exception) {
e.printStackTrace()
createAndShowForegroundNotification(this, NOTIFICATION_ID, e.message!!, false)
}
stopForeground(false)
stopSelf()
}
companion object {
val STATUS_FINISHED = 1
fun getNotificationBuilder(context: Context, channelId: String, importance: Int): NotificationCompat.Builder {
val builder: NotificationCompat.Builder
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance)
builder = NotificationCompat.Builder(context, channelId)
} else {
builder = NotificationCompat.Builder(context)
}
return builder
}
@TargetApi(26)
private fun prepareChannel(context: Context, id: String, importance: Int) {
val appName = context.getString(R.string.app_name)
val description = "Testing Log Service"
val nm = context.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
if (nm != null) {
var nChannel: NotificationChannel? = nm.getNotificationChannel(id)
if (nChannel == null) {
nChannel = NotificationChannel(id, appName, importance)
nChannel.description = description
nm.createNotificationChannel(nChannel)
}
}
}
}
}
LogSendService class (Foreground service)
class LogWriteService : Service() {
private val NOTIFICATION_ID = 12345
internal var allLogFile: File? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
inner class MyBinder : Binder() {
val service: LogWriteService
get() = this@LogWriteService
}
override fun onCreate() {
super.onCreate()
// startLogService();
createAndShowForegroundNotification(this, NOTIFICATION_ID, "We are gathering logs", true)
writeLogs()
}
private fun createAndShowForegroundNotification(yourService: Service, notificationId: Int, message: String, isOnGoing: Boolean) {
val builder = getNotificationBuilder(yourService,
"Log Service", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW) //Low importance prevent visual appearance for this notification channel on top
builder.setSmallIcon(R.mipmap.home_icon)
.setContentTitle(yourService.getString(R.string.app_name))
.setContentText(message)
if (isOnGoing) {
builder.setOngoing(true)
}
val notification = builder.build()
yourService.startForeground(notificationId, notification)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return Service.START_STICKY
}
private fun writeLogs() {
try {
//log write and upload
} catch (e: Exception) {
e.printStackTrace()
createAndShowForegroundNotification(this, NOTIFICATION_ID, e.message!!, false)
}
stopForeground(false)
stopSelf()
}
companion object {
val STATUS_FINISHED = 1
fun getNotificationBuilder(context: Context, channelId: String, importance: Int): NotificationCompat.Builder {
val builder: NotificationCompat.Builder
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance)
builder = NotificationCompat.Builder(context, channelId)
} else {
builder = NotificationCompat.Builder(context)
}
return builder
}
@TargetApi(26)
private fun prepareChannel(context: Context, id: String, importance: Int) {
val appName = context.getString(R.string.app_name)
val description = "Testing Log Service"
val nm = context.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
if (nm != null) {
var nChannel: NotificationChannel? = nm.getNotificationChannel(id)
if (nChannel == null) {
nChannel = NotificationChannel(id, appName, importance)
nChannel.description = description
nm.createNotificationChannel(nChannel)
}
}
}
}
}
Can some one please suggest solution ? or better way to do that?
Note : some code is in Java and some in Kotlin