Skip to content

pondersource/Android-Solid-Services

Repository files navigation

This project consists of three parts:

Android Solid Services app

This app allows you to do single Solid sign-in in Android ecosystem. Which will be used for other apps to communicate through this app to do access resources requests, resource management and contacts data modules on the already-logged-in users' pod. You can download the app from here at the moment.

How to use locally

This project built with an enhanced JDK (JBR v17.0.9). So in case of having any problem during the build process, it is recommended to set your JAVA_HOME variable to your JBR v17.0.9 path or JDK 17 in general. Gradle is the default build tool used in this project. In the root directory of the project run command:

./gradlew assembleDebug

You can find the generated .apk file in the path: ./app/build/outputs/apk/debug

You can open it for instance with Android Studio. It will take a while for the emulator to start up but then you'll be presented with a login screen and and you can log in to your pod there. Here are some screenshots from the application:

Screenshot_20241218_152823 Screenshot_20241218_152854 Screenshot_20241218_152906 Screenshot_20241218_152952

Solid Android Client library

This android library has the responsibility to check your app already has access grant, request to access the pod resources, resource management requests and access data modules (currently Contacts data module). you can add this library to your android project by adding this line to your module-level build.gradle.kts file :

dependencies {
    ...
    implementation("com.pondersource.solidandroidclient:solidandroidclient:0.2.0")
}

or if you are using another building system, check here.

All the requests handled by Android Inter-processes Communication with Android Solid Services app. Before using any service you check if the service is already connected and then do your requests. For the authentication you can use this code:

val solidSignInClient = Solid.getSignInClient(context)
solidSignInClient.authServiceConnectionState().collect { hasConnected ->
    if(hasConnected) {
        //Auth service has connected
        
        //This code returens your account if you already have access, null if you don't have access.
        val account = solidSignInClient.getAccount()
        
        if (account == null) {
            solidSignInClient).requestLogin { granted, exception ->
                if (exception == null) {
                    if (granted == true) {
                        //User gave access grant to your app
                    } else {
                        //User declined your access grant request
                    }
                } else {
                    //Some error happened during the access request.
                }
            }
        }
    } else {
        //Auth service hasn't been connected and you can show a message to user
    }
}

After this step you can request for resources or data modules. Resources must inherited from com.pondersource.shared.resource.Resource or for better implementation, com.pondersource.shared.RDFSource or com.pondersource.shared.NonRDFSource. Depending on your data class, you can choose one. NonRDFSource used for raw files and resources without structure such as .txt, image files and etc. However, RDFSource used for data classes in format of RDF (common in Solid ecosystem). You can do the main four functions similar to this code:

val resourceClient = Solid.getResourceClient(context)

resourceClient.resourceServiceConnectionState().collect { hasConnected ->
    if(hasConnected) {
        //Service has connected and you can call methods below.
    } else {
        //Service has not been connected.
    }
}

//Read
resourceClient.read(RESOURCE_URL, YOUR_CLASS::class.java, object : SolidResourceCallback<YOUR_CLASS> {
    override fun onResult(result: YOUR_CLASS) {}

    override fun onError(exception: SolidException.SolidResourceException) {}
})

//Create
resourceClient.create(RESOURCE_OBJ, object : SolidResourceCallback<RESOURCE_OBJ_CLASS_TYPE> {
    override fun onResult(result: RESOURCE_OBJ_CLASS_TYPE) {}

    override fun onError(exception: SolidException.SolidResourceException) {}
})

//Update - for already existed resource
resourceClient.create(RESOURCE_OBJ, object : SolidResourceCallback<RESOURCE_OBJ_CLASS_TYPE> {
    override fun onResult(result: RESOURCE_OBJ_CLASS_TYPE) {}

    override fun onError(exception: SolidException.SolidResourceException) {}
})

//Delete - for already existed resource
resourceClient.delete(RESOURCE_OBJ, object : SolidResourceCallback<RESOURCE_OBJ_CLASS_TYPE> {
    override fun onResult(result: RESOURCE_OBJ_CLASS_TYPE) {}

    override fun onError(exception: SolidException.SolidResourceException) {}
})

In case your data classes are contacts, you can use contacts data modules functions:

val contactsDataModule = Solid.getContactsDataModule(context)

contactsDataModule.contactsDataModuleServiceConnectionState().collect { hasConnected ->
    if(hasConnected) {
        //Service has connected and you can call methods below.
    } else {
        //Service has not been connected.
    }
}

contactsDataModule.getAddressBooks()
contactsDataModule.getAddressBook(ADDRESSBOOK_URI)
contactsDataModule.getContact(CONTACT_URI)
contactsDataModule.getGroup(GROUP_URI)
//Check the module class for more functions on address books.

For seeing some examples, you can refer to Solid Contacts app which works with Solid Contacts data module based on this library.

Solid Android API library

This library is used in the Android Solid Services app to interact with Solid. In case you have any problem with installing the app or want to connect to Solid directly you can add it to your android project by adding this line to your module level build.gradle.kts file.

dependencies {
    ...
    implementation("com.pondersource.solidandroidapi:solidandroidapi:0.2.0")
}

or if you are using another building system, check here.

For authentication, you can use: com.pondersource.solidandroidapi.AuthenticatorImplementation.getInstance(context). There are couple of steps to authenticate user with OpenId protocol such as register your app to OpenId and then ask for the intent to transfer the user to browser to enter their username/password of the selected IDP. For a better understanding please refer to Android Solid Services app codes.

After authenticating successfully, you can interact with Solid resources and data modules similar to what have been explained in Solid Android Client section with the difference that need to get the class instance with:

val resourceManager = com.pondersource.solidandroidapi.SolidResourceManagerImplementation.getInstance(context)
val contactModule = com.pondersource.solidandroidapi.SolidContactsDataModuleImplementation.getInstance(context)

For a better understanding of the project structure you can refer to this diagram: AndroidSolidServices (1)

Acknowledgments

Thanks to funding from NLnet /