33
loading...
This website collects cookies to deliver better user experience
AndroidManifest.xml
and locate the package name of your app. It should look something like com.example.myapplication
.mavenCentral()
repository to your project's build.gradle
file ( if it's not already present ).allprojects {
repositories {
google()
mavenCentral()
}
}
build.gradle
file.dependencies {
// ... Other dependencies
implementation 'io.appwrite:sdk-for-android:0.0.1'
}
android {
// ...
buildFeatures {
dataBinding true
}
}
Client()
class from the Appwrite SDK. For this, we will create a new file utils/Client.kt
where we will create a Singleton object to use across our App.package com.example.myapplication.utils
import android.content.Context
import io.appwrite.Client
object Client {
lateinit var client : Client
fun create(context: Context) {
client = Client(context)
// Replace with your own endpoint and project ID
.setEndpoint("https://demo.appwrite.io/v1")
.setProject("6070749e6acd4")
}
}
If your Appwrite setup is running on localhost, you will need to make sure localhost is accessible from your emulator by using a proxy. Else, you can replace localhost
with your private IP address which you can find using the command hostname -I
on UNIX systems.
setSelfSigned(true)
flag to true.client = Client(context)
.setEndpoint("https://192.168.1.35/v1")
.setProject("6070749e6acd4")
.setSelfSigned(true)
utils/Event.kt
. This utility class will allow us to handle LiveData Events ( Changes that need to be observed only once ).package com.example.myapplication.utils
/**
* Used as a wrapper for data that is exposed via a LiveData that represents an event.
*/
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
activity_main.xml
to allow us to host fragments. Replace the contents of activity_main.xml
with this snippet.<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
layout/fragment_account.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<EditText
android:id="@+id/responseTV"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@null"
android:enabled="true"
android:fadeScrollbars="false"
android:focusable="true"
android:longClickable="true"
android:scrollbars="vertical"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="Email"
android:inputType="textEmailAddress"
android:text="[email protected]"
app:layout_constraintStart_toStartOf="@id/responseTV"
app:layout_constraintTop_toBottomOf="@id/responseTV" />
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="password"
android:inputType="textPassword"
android:text="testtest"
app:layout_constraintStart_toStartOf="@id/email"
app:layout_constraintTop_toBottomOf="@id/email" />
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="name"
android:inputType="text"
app:layout_constraintStart_toStartOf="@id/password"
app:layout_constraintTop_toBottomOf="@id/password" />
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Login"
app:layout_constraintEnd_toStartOf="@+id/signup"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/name" />
<Button
android:id="@+id/signup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Signup"
app:layout_constraintEnd_toStartOf="@id/getUser"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/login"
app:layout_constraintTop_toBottomOf="@+id/name" />
<Button
android:id="@+id/getUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Get User"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/signup"
app:layout_constraintTop_toBottomOf="@+id/name" />
<Button
android:id="@+id/oAuth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Login with Facebook"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@+id/logout"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/signup" />
<Button
android:id="@+id/logout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/oAuth"
app:layout_constraintTop_toTopOf="@id/oAuth" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>
ui/accounts/AccountsViewModel.kt
to manage our app state.package com.example.myapplication.ui.accounts
import android.text.Editable
import androidx.activity.ComponentActivity
import androidx.lifecycle.*
import com.example.myapplication.utils.Client.client
import com.example.myapplication.utils.Event
import io.appwrite.exceptions.AppwriteException
import io.appwrite.services.Account
import kotlinx.coroutines.launch
import org.json.JSONObject
class AccountsViewModel : ViewModel() {
private val _error = MutableLiveData<Event<Exception>>().apply {
value = null
}
val error: LiveData<Event<Exception>> = _error
private val _response = MutableLiveData<Event<String>>().apply {
value = null
}
val response: LiveData<Event<String>> = _response
private val accountService by lazy {
Account(client)
}
fun onLogin(email: Editable , password : Editable) {
viewModelScope.launch {
try {
var response = accountService.createSession(email.toString(), password.toString())
var json = response.body?.string() ?: ""
json = JSONObject(json).toString(8)
_response.postValue(Event(json))
} catch (e: AppwriteException) {
_error.postValue(Event(e))
}
}
}
fun onSignup(email: Editable , password : Editable, name: Editable) {
viewModelScope.launch {
try {
var response = accountService.create(email.toString(), password.toString(), name.toString())
var json = response.body?.string() ?: ""
json = JSONObject(json).toString(2)
_response.postValue(Event(json))
} catch (e: AppwriteException) {
_error.postValue(Event(e))
}
}
}
fun onGetUser() {
viewModelScope.launch {
try {
var response = accountService.get()
var json = response.body?.string() ?: ""
json = JSONObject(json).toString(2)
_response.postValue(Event(json))
} catch (e: AppwriteException) {
_error.postValue(Event(e))
}
}
}
fun onLogout() {
viewModelScope.launch {
try {
var response = accountService.deleteSession("current")
var json = response.body?.string()?.ifEmpty { "{}" }
json = JSONObject(json).toString(4)
_response.postValue(Event(json))
} catch (e: AppwriteException) {
_error.postValue(Event(e))
}
}
}
}
ui/accounts/AccountsFragment.kt
package com.example.myapplication.ui.accounts
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.myapplication.R
import com.example.myapplication.databinding.FragmentAccountBinding
class AccountsFragment : Fragment() {
private lateinit var binding: FragmentAccountBinding
private lateinit var viewModel: AccountsViewModel
override fun onCreateView(
inflater: LayoutInflater ,
container: ViewGroup? ,
savedInstanceState: Bundle?
): View {
viewModel = ViewModelProvider(this).get(AccountsViewModel::class.java)
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_account,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
binding.login.setOnClickListener{
viewModel.onLogin(binding.email.text, binding.password.text)
}
binding.signup.setOnClickListener{
viewModel.onSignup(binding.email.text, binding.password.text, binding.name.text)
}
binding.getUser.setOnClickListener{
viewModel.onGetUser()
}
binding.logout.setOnClickListener{
viewModel.onLogout()
}
viewModel.error.observe(viewLifecycleOwner, Observer { event ->
event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
}
})
viewModel.response.observe(viewLifecycleOwner, Observer { event ->
event?.getContentIfNotHandled()?.let {
binding.responseTV.setText(it)
}
})
return binding.root
}
}
Client
singleton and add the AccountsFragment
to the FragmentContainerView.package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.add
import androidx.fragment.app.commit
import com.example.myapplication.utils.Client
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Client.create(applicationContext)
if (savedInstanceState == null) {
supportFragmentManager.commit {
setReorderingAllowed(true)
add<AccountsFragment>(R.id.fragment_container_view)
}
}
}
}
AndroidManifest.xml
file.<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<application
<!-- Other Activities -->
<activity android:name="io.appwrite.views.CallbackActivity" >
<intent-filter android:label="android_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="appwrite-callback-6070749e6acd4" />
</intent-filter>
</activity>
</application>
</manifest>
<data android:scheme="appwrite-callback-[PROJECT-ID]" />
with your own.createOAuth2Session()
method of the Appwrite SDK.fun oAuthLogin(activity: ComponentActivity) {
viewModelScope.launch {
try {
accountService.createOAuth2Session(activity, "facebook", "appwrite-callback-6070749e6acd4://demo.appwrite.io/auth/oauth2/success", "appwrite-callback-6070749e6acd4://demo.appwrite.io/auth/oauth2/failure")
} catch (e: Exception) {
_error.postValue(Event(e))
} catch (e: AppwriteException) {
_error.postValue(Event(e))
}
}
}
appwrite-callback-[PROJECT-ID]://[YOUR APPWRITE ENDPOINT]/auth/oauth2/[ success | failure ]
AccountsFragment.kt
override fun onCreateView(
inflater: LayoutInflater ,
container: ViewGroup? ,
savedInstanceState: Bundle?
): View? {
// ... Existing Methods
binding.oAuth.setOnClickListener{
viewModel.oAuthLogin(activity as ComponentActivity)
}
}