I need to connect my android app to an azure sql server to add to the sql server and population data from it in the app for school.
I’m not a great programmer, and don’t have much experience with Android and backend work.
Can anyone point me in the right direction on where to get started? I feel like anytime I see something for 2+ years ago the information is irrelevant.
I don’t need anything extravagant - bare bones is great.
Additionally, there seems to be more than one way to accomplish this? I see some mention jdbc and others mention rest api.
Here is the sample code for connecting SQL server from Android application.
package com.javahelps.usermanagement
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.Toast
import com.javahelps.usermanagement.service.Model
import com.javahelps.usermanagement.service.ServiceFactory
import com.javahelps.usermanagement.service.UserService
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private val service by lazy {
val factory = ServiceFactory.getInstance("http://10.0.2.2:8080", "admin", "admin")
factory.build(UserService::class.java)
}
private var disposable: Disposable? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun createUser(view: View) {
// Construct a user object
val user = Model.User(
etUsername.text.toString(),
etPassword.text.toString(),
etName.text.toString(),
etEmail.text.toString()
)
this.disposable = this.service.create(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ showResult("Successfully created the new user ${user.username}") },
{ showResult("Failed to create the new user!") })
}
fun readUser(view: View) {
val username = etUsername.text.toString()
this.disposable = this.service.read(username)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ user ->
run {
etUsername.setText(user.username)
etPassword.setText(user.password)
etName.setText(user.name)
etEmail.setText(user.email)
}
},
{ showResult("Failed to read the user $username") })
}
fun updateUser(view: View) {
val username = etUsername.text.toString()
// Construct a user object
val user = Model.User(
etUsername.text.toString(),
etPassword.text.toString(),
etName.text.toString(),
etEmail.text.toString()
)
this.disposable = this.service.update(username, user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ showResult("Successfully updated the user $username") },
{ showResult("Failed to update the user $username") })
}
fun deleteUser(view: View) {
val username = etUsername.text.toString()
// Prevent from accidentally deleting the admin user
if ("admin" == username) {
showResult("Cannot delete admin!")
return
}
this.disposable = this.service.delete(username)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ showResult("Successfully deleted the user $username") },
{ showResult("Failed to delete the user $username") })
}
private fun showResult(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
override fun onPause() {
super.onPause()
disposable?.dispose()
}
}
For the required steps connecting sql server with android application follow this document.
Related
I'm building an app (android studio - java) for my several devices, the app won't be on app store.
I want to be able to update the app remotely automatically.
I figured out how to check the version against a server, however I still don't know how to automatically update the app whenever the is a new version.
Thanks a head!
Firstly, as you said, you need to check the latest version, online and locally.
Then you need to put the apk newest apk online
Finally, if the online version is ahead the local, you need to download the file and update the app.
The easiest way to do it is to use the ota_update package to download and update the app
I hope this solution is useful for you
First you have to store the latest version on the server side using API.
After that you have to compare the installed current app version to the server-side stored version if both are different and the current version lower than the server-side version at that time you have to perform the below code.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!getPackageManager().canRequestPackageInstalls()) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", getPackageName()))), 1234);
} else {
downloadController = new DownloadController(DashboardNewActivity.this, url);
downloadController.enqueueDownload();
}
}
Use this DownloadController.kt class
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.core.content.FileProvider
import com.app.golden.BuildConfig
import com.app.golden.R
import java.io.File
class DownloadController(private val context: Context, private val url: String) {
companion object {
private const val FILE_NAME = "company.apk"
private const val FILE_BASE_PATH = "file://"
private const val MIME_TYPE = "application/vnd.android.package-archive"
private const val PROVIDER_PATH = ".provider"
private const val APP_INSTALL_PATH = "\"application/vnd.android.package-archive\""
}
fun enqueueDownload() {
var destination = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/"
destination += FILE_NAME
val uri = Uri.parse("$FILE_BASE_PATH$destination")
val file = File(destination)
if (file.exists()) file.delete()
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadUri = Uri.parse(url)
val request = DownloadManager.Request(downloadUri)
request.setMimeType(MIME_TYPE)
request.setTitle(context.getString(R.string.app_name))
request.setDescription(context.getString(R.string.downloading))
// set destination
request.setDestinationUri(uri)
showInstallOption(destination, URI)
// Enqueue a new download and same the referenced
downloadManager.enqueue(request)
Toast.makeText(context, context.getString(R.string.downloading), Toast.LENGTH_LONG)
.show()
}
private fun showInstallOption(
destination: String,
uri: Uri
) {
// set BroadcastReceiver to install app when .apk is downloaded
val onComplete = object : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val contentUri = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + PROVIDER_PATH,
File(destination)
)
val install = Intent(Intent.ACTION_VIEW)
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
install.data = contentUri
context.startActivity(install)
context.unregisterReceiver(this)
} else {
val install = Intent(Intent.ACTION_VIEW)
install.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
install.setDataAndType(
uri,
APP_INSTALL_PATH
)
context.startActivity(install)
context.unregisterReceiver(this)
}
} catch (e: Exception) {
val data = e.message.toString()
Log.e("Exception: ", data)
}
}
}
context.registerReceiver(onComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
}
I am making a chat app and I am trying to make message notification.
I have a Firebase database that i store all my data (users, friends, messages). When user sends a message, app adds that message to firebase database ( path is "/notification/user_who_recived/user_who_send" ).
my problem is i cant make service that gets message in "/notification..../" path and makes notification based on message.
here is my test code that doesnt work:
package com.cagsak.chatapp
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
class background_service : Service(){
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
println("background_service: THREAD İS STARTED")
val uid = FirebaseAuth.getInstance().uid ?: stopSelf()
val ref = FirebaseDatabase.getInstance().getReference("/notifications/$uid")
ref.get()
.addOnSuccessListener { data_list ->
println("background_service: MESSAGE GETTING IS SUCCESSFUL")
data_list.children.forEach { child ->
val data = child.getValue(ChatMessage::class.java)
if (data != null) {
println("background_service: MESSAGE RECEIVER IS FOUND")
SendNotification(data, baseContext)
child.ref.removeValue().addOnSuccessListener {
println("background_service: MESSAGE DATA IS DELETED")
}
}
}
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
private fun SendNotification(message: ChatMessage, context: Context) {
FirebaseDatabase.getInstance()
.getReference("/users").get()
.addOnSuccessListener { userlist ->
userlist.children.forEach { user_data ->
val user = user_data.getValue(User::class.java)
if (user != null && user.uid == message.fromId) {
val intent = Intent(context, ChatMessage::class.java)
intent.putExtra("USERKEY", user)
val pendingIntent: PendingIntent =
PendingIntent.getActivity(context, 0, intent, 0)
NotificationCompat.Builder(context, "MY_CHANEL_ID")
.setSmallIcon(R.drawable.small_logo)
.setContentTitle(message.fromId)
.setContentText(message.text)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
}
}
}
}
}
Im trying to add the Google Android Consent SDK to Flutter and connect to it using a MethodChannel. I've got the form popping up successfully and I am able to return some info back to my main.dart file on the Flutter side.
I'm having trouble getting the users choice they selected from the Google Consent Form returned back to me to the Flutter side so I can then save whether they selected to see PERSONALIZED or NON-PERSONALIZED ads back in my main.dart file. Im just using the boilerplate Flutter example app to achieve this. Any help is greatly appreciated.
main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
static const CHANNEL = const MethodChannel("flutter.native/helper");
static const IS_EEA_OR_UNKNOWN_METHOD = "isEeaOrUnknown";
bool isEeaOrUnknown = true;
Future<bool> _isEeaOrUnknown() async {
var result = await CHANNEL.invokeMethod(IS_EEA_OR_UNKNOWN_METHOD);
if (result is bool) {
print("isEEAOrUnknown: $result");
return result;
} else {
print("WTF: $result");
return true;
}
}
void _callIsEea() {
_isEeaOrUnknown().then((result) {
Future.delayed(Duration(seconds: 3)).then((d) {
setState(() {
isEeaOrUnknown = result;
});
});
});
}
#override
void initState(){
super.initState();
_callIsEea();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"iisEeaOrUnknown: $isEeaOrUnknown",
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
MainActivity.kt
package com.example.flutter_consent
import android.os.Bundle
import com.google.ads.consent.DebugGeography
import com.google.ads.consent.ConsentStatus
import com.google.ads.consent.ConsentInfoUpdateListener
import com.google.ads.consent.ConsentInformation
import com.google.ads.consent.ConsentFormListener
import com.google.ads.consent.ConsentForm
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
import java.net.MalformedURLException
import java.net.URL
class MainActivity: FlutterActivity() {
var form: ConsentForm? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
print("NATIVE method call")
when (call.method) {
IS_EEA_METHOD_NAME -> {
print("NATIVE METHOD CALLED - $IS_EEA_METHOD_NAME")
isEeaOrUnknown(result)
}
else -> {
print("NATIVE METHOD CALL ERROR")
result.notImplemented()
}
}
}
}
private fun isEeaOrUnknown(result: MethodChannel.Result){
val consentInformation = ConsentInformation.getInstance(this)
//testing only
consentInformation.debugGeography = DebugGeography.DEBUG_GEOGRAPHY_EEA
//consentInformation.debugGeography = DebugGeography.DEBUG_GEOGRAPHY_NOT_EEA
consentInformation.requestConsentInfoUpdate(arrayOf(PUBLISHER_ID), object : ConsentInfoUpdateListener {
override fun onConsentInfoUpdated(consentStatus: ConsentStatus) {
when (consentStatus) {
ConsentStatus.PERSONALIZED -> {
print("User selected personalized")
}
ConsentStatus.NON_PERSONALIZED -> {
print("User non-personalized")
}
ConsentStatus.UNKNOWN -> {
print("UNKNOWN")
}
}
}
override fun onFailedToUpdateConsentInfo(errorDescription: String) {
print("ERROR $errorDescription")
result.success(consentInformation.isRequestLocationInEeaOrUnknown)
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
var privacyUrl: URL? = null
try {
privacyUrl = URL("http://www.privacyurl.com/")
} catch (e: MalformedURLException) {
e.printStackTrace()
// Handle error.
}
form = ConsentForm.Builder(this, privacyUrl).withListener(object : ConsentFormListener() {
override fun onConsentFormLoaded() {
// Consent form loaded successfully.
form!!.show()
}
override fun onConsentFormOpened() {
// Consent form was displayed.
}
override fun onConsentFormClosed(
consentStatus: ConsentStatus?, userPrefersAdFree: Boolean?) {
// Consent form was closed.
}
override fun onConsentFormError(errorDescription: String?) {
// Consent form error.
}
})
.withPersonalizedAdsOption()
.withNonPersonalizedAdsOption()
.build()
form!!.load()
}
companion object{
const val CHANNEL = "flutter.native/helper"
const val PUBLISHER_ID = "pub-xxxxxxxxxxxxxxx"
const val IS_EEA_METHOD_NAME = "isEeaOrUnknown"
}
}
so I have recently used scarlet WebSocket to successfully send data to my server online but the issue is that I am supposed to get a response from the server but am not getting anything.
below is my code:
class MainActivity : AppCompatActivity() {
#SuppressLint("CheckResult")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val socketInit = ServerClass(application)
socketInit.socket.observeWebSocketEvent()
.filter { it is WebSocket.Event.OnConnectionOpened<*> }
.subscribe({
val data = "{ \"lat\": 40.5555555555, \"lng\": 37.55564555554545, \"userId\": 2}"
val send = LocationAction(data =data)
socketInit.socket.subscribe(send)
Log.d("TAG_SUB",send.toString())
},{
Log.e("TAG", "Error while observing socket ${it.cause}")
})
socketInit.socket.observeTicker().subscribe({
idText.text =it
Log.d("TAG", "Observed: $it")
},
{
Log.e("TAG", "Error while observing ticker ${it.cause}")
})
}
}
here is my interface
interface SocketService {
#Receive
fun observeWebSocketEvent(): Flowable<WebSocket.Event>
#Send
fun subscribe(action: LocationAction)
#Receive
fun observeTicker(): Flowable<String>
}
this class bellow hold my scarlet implementation and my socket url
class ServerClass(application: Application): MainApplication() {
private val lifecycle = AndroidLifecycle.ofApplicationForeground(application = application)
private val backoffStrategy = ExponentialWithJitterBackoffStrategy(5000, 5000)
private val okHttpClient = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build()
val socket = Scarlet.Builder()
.webSocketFactory(okHttpClient.newWebSocketFactory("https://staging.kross.app/api/v1/notification/update"))
.addMessageAdapterFactory(MoshiMessageAdapter.Factory())
.addStreamAdapterFactory(RxJava2StreamAdapterFactory())
.backoffStrategy(backoffStrategy)
.lifecycle(lifecycle)
.build()
.create<SocketService>()
}
The observeTicker function should be where I listen for my response from the server but nothing is happening. Please I need help
I was experiencing the same problem, until I found a way to catch the messages coming from the socket.
I'm catching the messages this way:
socketInit.socket.observeWebSocketEvent()
.subscribe {
when (it) {
is WebSocketEvent.OnConnectionOpened -> {
//I do the Subscription Here the 1st message to the webserver
}
is WebSocketEvent.OnConnectionClosing -> {
//Connection Closing
}
is WebSocketEvent.OnConnectionFailed -> {
//If connection fails
}
is WebSocketEvent.OnMessageReceived -> {
//I'm doing it here!! If you parse the it.message.toString()
//You can transform the response into a JSON Object like this
val x : Response = Gson().fromJson(it.message.toString(), Response::class.java)
}
I hope this will help you
I'm using UrbanAirship for push notifications. Everything is working fine, but there are certain scenarios where I wouldn't like to display the push notification coming from urban. Do I have to handle this on the server side or can I handle it on the client side?
If possible, how would I handle this on the client side? I've tried canceling the notification, and that works, but it still displays the rollover message in the status bar.
You need to override Airship's notification factory for this:
package your.package;
import android.app.Notification;
import android.content.Context;
import android.support.annotation.NonNull;
import com.urbanairship.push.PushMessage;
import com.urbanairship.push.notifications.DefaultNotificationFactory;
public class PushNotificationFactory extends DefaultNotificationFactory {
public PushNotificationFactory(Context context) {
super(context);
}
public Notification createNotification(#NonNull PushMessage message, int notificationId) {
boolean shouldWeShowNotification = false; // your condition goes here
if (shouldWeShowNotification) {
return super.createNotification(message, notificationId);
} else {
return null;
}
}
}
and when taking off:
UAirship.takeOff(this, new UAirship.OnReadyCallback() {
#Override
public void onAirshipReady(UAirship airship) {
NotificationFactory notificationFactory = new PushNotificationFactory(getApplicationContext());
airship.getPushManager().setNotificationFactory(notificationFactory);
}
});
You need to create a BroadcastReceiver in your app to intercept the push. You can then choose to display a custom notification or not.
Check out the setup docs http://docs.urbanairship.com/build/android_features.html#set-up
If you're using Kotlin:
class PushNotificationFactory(context: Context) : NotificationFactory(context) {
override fun createNotification(message: PushMessage, notificationId: Int): Notification? {
val notificationWillBeShowed = false // your condition goes here
return if (notificationWillBeShowed) {
// Show notification
super.createNotification(message, notificationId)
} else {
// Prevent notification from showing
null
}
}
}
class UrbanAirshipAutopilot : Autopilot() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onAirshipReady(airship: UAirship) {
airship.pushManager.userNotificationsEnabled = true
val context = UAirship.getApplicationContext()
val notificationFactory = PushNotificationFactory(context)
airship.pushManager.notificationFactory = notificationFactory
if (Build.VERSION.SDK_INT >= 26) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val defaultChannelId = context.getString(R.string.notification_channel_id_default)
val defaultChannelName = context.getString(R.string.notification_channel_name_default)
val channel = NotificationChannel(defaultChannelId, defaultChannelName, NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
}
override fun createAirshipConfigOptions(context: Context): AirshipConfigOptions? {
val defaultChannelId = context.getString(R.string.notification_channel_id_default)
return AirshipConfigOptions.Builder()
.setDevelopmentAppKey(BuildConfig.URBAN_AIRSHIP_APP_KEY_DEVELOPMENT)
.setDevelopmentAppSecret(BuildConfig.URBAN_AIRSHIP_APP_SECRET_DEVELOPMENT)
.setProductionAppKey(BuildConfig.URBAN_AIRSHIP_APP_KEY_PRODUCTION)
.setProductionAppSecret(BuildConfig.URBAN_AIRSHIP_APP_SECRET_PRODUCTION)
.setInProduction(!BuildConfig.DEBUG)
.setGcmSender(BuildConfig.CLOUD_MESSAGING_SENDER_ID) // FCM/GCM sender ID
// .setNotificationIcon(R.drawable.ic_notification)
// .setNotificationAccentColor(ContextCompat(getContext(), R.color.accent))
.setNotificationChannel(defaultChannelId)
.build()
}
}