Unofficial Actions on Google SDK for Kotlin and Java

Overview

Actions On Google Client Library

This is a port of the official Node.js SDK to Kotlin. This can also be used from Java and any JVM language.

Quick Facts

  • Port of the actions-on-google SDK to Kotlin. Kotlin and Java developers can quickly start building Actions for Google Assistant.
  • Used in production for the Ticketmaster Assistant Action ("Ok Google, ask Ticketmaster to find rock concerts near me.")
  • Closely matches Node.js Client Library API
  • Closely matches implementation of Node.js sdk so code can be maintained easily as features are added
  • All tests ported from nodejs SDK (using Spek framework) & 100% passing
  • Dialogflow and Actions SDK support
  • Conversation Components & Transaction Sample ported
  • Supports v2 of Actions on Google API (if v1 is needed, make an issue please)

V2 Support

The V2 release is available by using:

    compile 'com.tmsdurham.actions:actions-on-google:2.0.2'

The V2 is mostly complete, but may have a few bugs and missing features. All Conversation components and Transaction API are working. Dialogflow & ActionSDK has been tested and working. The API matches the official node.js API very closely. The sample in this repo is a good place to get started. The setup and samples in this readme have not been updated yet. There are a few differerences and additions:

* use action name from Dialogflow instead of intent name.  The official library changed from using the action field, to using the intent name.  There is a PR open on the official SDK for support for action.  If/when this is merged, this library will be updated to match.
* middleware not supported.  Same functionality can be implemented without lib support by wrapping handlers in fuctions.

V2 notes: A common module was used with the intent on targeting multiple platforms (JS & possibly native). These other platforms are purely experimental at this time. A single code base for JVM and JS would be more efficient.

Setup Instructions(V1 - see sample for V2 setup and use)

This library is available on jCenter. If your using gradle simply add the dependency as follows:

Gradle:

repositories {
        jCenter()
    }
}

dependencies {
    compile 'com.tmsdurham.actions:actions-on-google:1.6.0'
}

Maven:

<dependency>
	<groupId>com.tmsdurham.actions</groupId>
	<artifactId>actions-on-google</artifactId>
	<version>1.6.0</version>
	<type>pom</type>
</dependency>

The above artifact should fit the needs of most developers, however, if you are not using java.servlet.http.HttpServlet, or do not want to use Gson for deserialization, you can use the actions-on-google-core lib. For example how to use the core library, reading through the sdk-gson-servlet module.

Gradle:

compile 'com.tmsdurham.actions:actions-on-google-core:1.6.0'. //only if not using Servlets

Maven:

<dependency>
	<groupId>com.tmsdurham.actions</groupId>
	<artifactId>actions-on-google-core</artifactId>		//only if not using Servlets
	<version>1.6.0</version>
	<type>pom</type>
</dependency>

Using Kotlin

fun welcome(app: DialogflowApp) =
    app.ask(app.buildRichResponse()
            .addSimpleResponse(speech = "Hi there!", displayText = "Hello there!")
            .addSimpleResponse(
                    speech = """I can show you basic cards, lists and carousels as well as
                "suggestions on your phone""",
                    displayText = """"I can show you basic cards, lists and carousels as
                "well as suggestions"""")
            .addSuggestions("Basic Card", "List", "Carousel", "Suggestions"))
            
fun normalAsk(app: DialogflowApp) = app.ask("Ask me to show you a list, carousel, or basic card")

fun suggestions(app: DialogflowApp) {
    app.ask(app
        .buildRichResponse()
        .addSimpleResponse("This is a simple response for suggestions")
        .addSuggestions("Suggestion Chips")
        .addSuggestions("Basic Card", "List", "Carousel")
        .addSuggestionLink("Suggestion Link", "https://assistant.google.com/"))
}

val actionMap = mapOf(
    WELCOME to ::welcome,
    NORMAL_ASK to ::normalAsk,
    SUGGESTIONS to ::suggestions)
  

@WebServlet("/conversation")
class WebHook : HttpServlet() {

	override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
    	DialogflowAction(req, resp).handleRequest(actionMap)
   }
}

Using Java

@WebServlet("/conversation/java")
public class ConversationComponentsSampleJava extends HttpServlet {
	private static final Logger logger = Logger.getAnonymousLogger();

	Function1<DialogflowApp, Object> welcome = app -> {
    	app.ask(app.buildRichResponse()
            .addSimpleResponse("Hi there from Java!", "Hello there from Java!")
            .addSimpleResponse(
                    "I can show you basic cards, lists and carousels as well as suggestions on your phone",
                    "I can show you basic cards, lists and carousels as well as suggestions")
            .addSuggestions("Basic Card", "List", "Carousel", "Suggestions"), null);
    	return Unit.INSTANCE;
	};

	Function1<DialogflowApp, Object> normalAsk = app ->
   	     app.ask("Ask me to show you a list, carousel, or basic card");

	Function1<DialogflowApp, Object> suggestions = app ->
   	     app.ask(app.buildRichResponse(null)
                .addSimpleResponse("This is a simple response for suggestions", null)
                .addSuggestions("Suggestion Chips")
                .addSuggestions("Basic Card", "List", "Carousel")
                .addSuggestionLink("Suggestion Link", "https://assistant.google.com/"));

	private Map<String, Function1<String, Object>> intentMap = new HashMap() {{
    	put(ConversationComponentsSampleKt.WELCOME, welcome);
    	put(ConversationComponentsSampleKt.NORMAL_ASK, normalAsk);
    	put(ConversationComponentsSampleKt.SUGGESTIONS, suggestions);
	}};

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     	 DialogflowAction action = new DialogflowAction(req, resp);
   	 	 action.handleRequest(intentMap);
	}
}

Extending to other Platforms

Dialogflow can be integrated with other platforms, such as Facebook Messenger, Slack, etc. Actions-on-Goolge-kotlin can be extended and data for those platforms returned from your webhook. To do this, simply add to the data for your platform using the app.data function. This must be done before calling the ask function.

val app = DialogflowAction(resp, req, gson)
val facebookResponse = //build response with your choice of method
app.data {
	this["facebook"] = facebookMessages
}
app.ask("Hello facebook users!")

The objects in the data object will be passed to the original platform. It may also be used to send custom data back in the response to the /query rest endpoint. More info on this is in the Dialogflow docs.

License

See LICENSE.md.

Comments
  • action not recognized?

    action not recognized?

    Hello, I'm experiencing some problem with your library. I'm using your code to recognize the action after a request:

    My intent action return "tell.popular" (this is the request that Dialogflow sends):

    {
      "responseId": "589e1fb4-56b6-4377-8944-16b442090958",
      "queryResult": {
        "queryText": "popolare",
        **"action": "tell.popular",**
        "parameters": {
          "Filtro": "Popolarità"
        },
        "allRequiredParamsPresent": true,
        "fulfillmentMessages": [
          {
            "text": {
              "text": [
                ""
              ]
            }
          }
        ],
        "intent": {
          "name": "projects/nespressoadvisor/agent/intents/bb7a2662-2851-4d68-bb86-92d368b6d195",
          "displayName": "choose_popular"
        },
        "intentDetectionConfidence": 1,
        "diagnosticInfo": {},
        "languageCode": "it"
      },
      "webhookStatus": {
        "message": "Webhook execution successful"
      }
    }
    

    and here is the code. Unfortunately it doesn't work and I can't find a way to check the whole flow from handleRequest(actionMap) and check how is managed the request.

    Furthermore, if I try to evaluate the DialogflowAction(req, res).handleRequest(actionMap) line during debug, it returns me "undefined". (???)

    Could you help me?

    const val POPULAR = "tell.popular"
    
    @WebServlet(name = "Hello", value = "/")
    class HomeController : HttpServlet() {
    
        val actionMap = mapOf(POPULAR to ::popular)
    
    
        fun popular(app: DialogflowApp) =
                app.ask(app.buildRichResponse()
                        .addSimpleResponse(speech = "Hi there!", displayText = "Hello there!")
                        .addSimpleResponse(
                                speech = """I can show you basic cards, lists and carousels as well as suggestions on your phone""",
                                displayText = """I can show you basic cards, lists and carousels as well as suggestions""")
                        .addSuggestions("Basic Card", "List", "Carousel", "Suggestions"))
    
    
    
        override fun doPost(req: HttpServletRequest, res: HttpServletResponse) {
    
    
            DialogflowAction(req, res).handleRequest(actionMap)
    
        }
    
    opened by davidmarinangeli 4
  • Fill displayText in DialogflowResponse body

    Fill displayText in DialogflowResponse body

    Using the following code:

    @PostMapping("/")
    fun intentMapper(req: HttpServletRequest, res: HttpServletResponse) {
        DialogflowAction(req, res).handleRequest(mapOf("testAction" to ::test))
    }
    
    fun test(action: DialogflowApp) {
        action.tell(speech="Text to speech", displayText="Text to display")
    }
    

    the response body fullfilment looks like this:

    "fulfillment": {
          "speech": "Text to speech",
          "source": "",
          "displayText": "",   <-------------------------------- SHOULD NOT BE EMPTY
          "messages": [
            {
              "type": 0,
              "speech": "Text to speech"
            }
          ],
          "data": {
            "google": {
              "isSsml": false,
              "noInputPrompts": [],
              "expectUserResponse": false,
              "richResponse": {
                "items": [
                  {
                    "simpleResponse": {
                      "textToSpeech": "Text to speech",
                      "displayText": "Text to display"
                    }
                  }
                ],
                "suggestions": []
              }
            }
          }
        }
    

    We can access to the displayText of fulfillment.data.google.richResponse.items[0].simpleResponse.displayText.

    However, I was expecting the same text in displayText at fulfillment.displayText like fulfillment.speech, but it is empty.

    opened by Carleslc 3
  • Is this v2 version stable

    Is this v2 version stable

    Just getting started on google actions v2. Wondering if you consider this library is stable enough to use?

    https://bintray.com/patjackson52/maven/com.tmsdurham.actions/2.0.3-alpha

    opened by scottlahay 1
  • Sample DF app not working?

    Sample DF app not working?

    The problem

    Hi Patrick, I know you will hate me for all these issues 😛 but I'm experiencing other problems with your sample.

    In fact, if I say "list" or "basic card" it doesn't catch the appropriate intent. Furthermore, ANY response tested on Google Assistant simulator gives me error and tells me 'final_response' must be set.

    The problems is obviously extended also on my projects: in fact none of the samples copied and paste on my code don't work on Google Assistant simulator.

    Some debugging

    I've tried to write down manually the same structure of JSON for the response and here is what i found:

    Manually built response through Google Assistant tab on Dialogflow

    {
       "id":"a0e829f0-1dec-4624-9726-d76e2a6df19d",
       "timestamp":"2018-05-01T14:33:23.67Z",
       "lang":"it",
       "result":{
          "source":"agent",
          "resolvedQuery":"popolare",
          "action":"tell.popular",
          "actionIncomplete":false,
          "parameters":{
             "Filtro":"Popolarità"
          },
          "contexts":[
             {
                "name":"_actions_on_google_",
                "parameters":{
                   "Filtro":"Popolarità",
                   "Filtro.original":"popolare"
                },
                "lifespan":99
             }
          ],
          "metadata":{
             "intentId":"bb7a2662-2851-4d68-bb86-92d368b6d195",
             "webhookUsed":"false",
             "webhookForSlotFillingUsed":"false",
             "intentName":"choose_popular"
          },
          "fulfillment":{
             "speech":"",
             "messages":[
                {
                   "type":"simple_response",
                   "platform":"google",
                   "textToSpeech":"Hello my friend"
                },
                {
                   "type":"suggestion_chips",
                   "platform":"google",
                   "suggestions":[
                      {
                         "title":"this"
                      },
                      {
                         "title":"or"
                      },
                      {
                         "title":"that"
                      }
                   ]
                },
                {
                   "type":0,
                   "speech":""
                }
             ]
          },
          "score":1
       },
       "status":{
          "code":200,
          "errorType":"success",
          "webhookTimedOut":false
       },
       "sessionId":"adf3ea83-cc0e-410c-b642-28300d81549a"
    }
    

    and below you can see response coming from webhook:

    {
       "id":"513f3256-2e9c-4c94-93a4-1bfdb408a9b0",
       "timestamp":"2018-05-01T14:34:18.722Z",
       "lang":"it",
       "result":{
          "source":"agent",
          "resolvedQuery":"popolare",
          "action":"tell.popular",
          "actionIncomplete":false,
          "parameters":{
             "Filtro":"Popolarità"
          },
          "contexts":[
             {
                "name":"_actions_on_google_",
                "parameters":{
                   "Filtro":"Popolarità",
                   "Filtro.original":"popolare"
                },
                "lifespan":100
             }
          ],
          "metadata":{
             "intentId":"bb7a2662-2851-4d68-bb86-92d368b6d195",
             "webhookUsed":"true",
             "webhookForSlotFillingUsed":"false",
             "webhookResponseTime":297,
             "intentName":"choose_popular"
          },
          "fulfillment":{
             "speech":"Hi there from Java!",
             "source":"",
             "messages":[
                {
                   "type":0,
                   "speech":"Hi there from Java!"
                }
             ],
             "data":{
                "google":{
                   "isSsml":false,
                   "noInputPrompts":[
    
                   ],
                   "expectUserResponse":true,
                   "richResponse":{
                      "items":[
                         {
                            "simpleResponse":{
                               "textToSpeech":"Hi there from Java!",
                               "displayText":"Hello there from Java!"
                            }
                         }
                      ],
                      "suggestions":[
                         {
                            "title":"hello"
                         },
                         {
                            "title":"hi"
                         }
                      ]
                   }
                }
             }
          },
          "score":1
       },
       "status":{
          "code":200,
          "errorType":"success",
          "webhookTimedOut":false
       },
       "sessionId":"adf3ea83-cc0e-410c-b642-28300d81549a"
    }
    

    As you can see, in the fulfillment object is really different for the "messages" and "data" object: what's happening?

    opened by davidmarinangeli 1
  • Refactors isEmpty() methods to empty()

    Refactors isEmpty() methods to empty()

    The presence of isEmpty() causes some kotlin JSON parsers (e.g. fasterxml as used by AWS Lambda) to generate a field labelled 'empty' because isEmpty() follows the pattern of a boolean accessor.

    opened by louth 1
  • askForUpdatePermission doesn't find my intent even though it is clearly there

    askForUpdatePermission doesn't find my intent even though it is clearly there

    Hi, I've been struggling with this for a few days now.

    askForUpdatePermission doesn't find my intent even though it is clearly there. Can someone please help point in the right direction?

    1. askForUpdatePermission not finding intent

    I followed the Update Sample at https://github.com/actions-on-google/dialogflow-updates-nodejs and got the update permission to work.

    But when I added app.askForUpdatePermission("get.next.reminder") into my own code, the simulator says that my agent is not responding. I did not get the question to give update permission.

    In the simulator error tab, I see an error:

    MalformedResponse expected_inputs[0].possible_intents[0].input_value_data: The intent the app is asking for permission to send updates for is not found.. So I checked the intent name (get.next.reminder) again in my agent and it is clearly there and mapped to an action. I also tested that this intent can be triggered by user input.

    The response tab shows the response like this:

    { "conversationToken": "["actions_on_google"]", "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "PLACEHOLDER_FOR_PERMISSION" } } ] } }, "possibleIntents": [ { "intent": "actions.intent.PERMISSION", "inputValueData": { "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec", "permissions": [ "UPDATE" ], "updatePermissionValueSpec": { "intent": "get.next.reminder" } } } ] } ], "responseMetadata": { "status": { "message": "Success (200)" }, "queryMatchInfo": { "queryMatched": true, "intent": "d7edc1c1-1c67-49af-89bb-37e17ed35025" } } } Where I see PLACEHOLDER_FOR_PERMISSION in the response text.

    Not sure why it is not finding the intent. Can anyone please please help with this?

    1. How to remove permissions?

    Also, a separate but related question: once you give the permission, how can you remove it? This is really important to be able to test.

    Thank you.

    https://stackoverflow.com/questions/49661752/dialogflowapp-askforupdatepermission-not-working

    opened by clarako 0
  • Mocking framework

    Mocking framework

    Hi,

    hope find you well with this cold call.

    I am an author of mocking framework for Kotlin

    I see you are using mockito-kotlin.

    I just want you to be aware that there is solution that fully supports Kotlin and ask to try it in your new/current projects.

    I can help you if you answer to this issue.

    Thanks and please star it

    opened by oleksiyp 0
  • Configure Renovate

    Configure Renovate

    Mend Renovate

    Welcome to Renovate! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.

    🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.


    Detected Package Files

    • settings.gradle (gradle)
    • build.gradle (gradle)
    • common/build.gradle (gradle)
    • common-mock/build.gradle (gradle)
    • js/build.gradle (gradle)
    • js-app/build.gradle (gradle)
    • jvm/build.gradle (gradle)
    • jvm-app/build.gradle (gradle)
    • sample-gae-jvm/build.gradle (gradle)
    • gradle/wrapper/gradle-wrapper.properties (gradle-wrapper)

    Configuration

    🔡 Renovate has detected a custom config for this PR. Feel free to ask for help if you have any doubts and would like it reviewed.

    Important: Now that this branch is edited, Renovate can't rebase it from the base branch any more. If you make changes to the base branch that could impact this onboarding PR, please merge them manually.

    What to Expect

    With your current configuration, Renovate will create 12 Pull Requests:

    Update dependency com.google.appengine:appengine-api-1.0-sdk to v1.9.98
    Update dependency com.jfrog.bintray.gradle:gradle-bintray-plugin to v1.8.5
    • Schedule: ["at any time"]
    • Branch name: renovate/com.jfrog.bintray.gradle-gradle-bintray-plugin-1.x
    • Merge into: master
    • Upgrade com.jfrog.bintray.gradle:gradle-bintray-plugin to 1.8.5
    Update dependency com.google.code.gson:gson to v2.10
    • Schedule: ["at any time"]
    • Branch name: renovate/com.google.code.gson-gson-2.x
    • Merge into: master
    • Upgrade com.google.code.gson:gson to 2.10
    Update dependency com.moowork.gradle:gradle-node-plugin to v1.3.1
    • Schedule: ["at any time"]
    • Branch name: renovate/com.moowork.gradle-gradle-node-plugin-1.x
    • Merge into: master
    • Upgrade com.moowork.gradle:gradle-node-plugin to 1.3.1
    Update dependency gradle to v4.10.3
    • Schedule: ["at any time"]
    • Branch name: renovate/gradle-4.x
    • Merge into: master
    • Upgrade gradle to 4.10.3
    Update dependency junit:junit to v4.13.2
    • Schedule: ["at any time"]
    • Branch name: renovate/junit-junit-4.x
    • Merge into: master
    • Upgrade junit:junit to 4.13.2
    Update dependency org.mockito:mockito-core to v2.28.2
    • Schedule: ["at any time"]
    • Branch name: renovate/mockito-monorepo
    • Merge into: master
    • Upgrade org.mockito:mockito-core to 2.28.2
    Update kotlin monorepo to v1.7.21
    Update dependency com.google.appengine:appengine-api-1.0-sdk to v2
    Update dependency gradle to v7
    • Schedule: ["at any time"]
    • Branch name: renovate/gradle-7.x
    • Merge into: master
    • Upgrade gradle to 7.5.1
    Update dependency javax.servlet:javax.servlet-api to v4
    Update dependency org.mockito:mockito-core to v4
    • Schedule: ["at any time"]
    • Branch name: renovate/major-mockito-monorepo
    • Merge into: master
    • Upgrade org.mockito:mockito-core to 4.9.0

    🚸 Branch creation will be limited to maximum 2 per hour, so it doesn't swamp any CI resources or spam the project. See docs for prhourlylimit for details.


    ❓ Got questions? Check out Renovate's Docs, particularly the Getting Started section. If you need any further assistance then you can also request help here.


    This PR has been generated by Mend Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Unable to resolve com.ticketmaster.actions:common:2.0.2

    Unable to resolve com.ticketmaster.actions:common:2.0.2

    This is my gradle import. I am unable to import the library in gradle. Getting a red line under com.ticketmaster.actions:common:2.0.2.

    repositories {
        mavenCentral()
        jcenter()
    }
    
    dependencies {
        compile 'com.tmsdurham.actions:actions-on-google:2.0.2'
    
    }
    
    opened by adrian-soon 1
  • Working on getting a simple v2 example going. Need some guidance

    Working on getting a simple v2 example going. Need some guidance

    I have been working on a google app engine project using the v2 branch. Looking for some guidence. I copied the DialogflowWebhook example and got a late init error that went away when I set Serializer.aogGson = Gson()

    now I'm getting this exception

    Uncaught exception from servlet java.lang.Error: No response has been set. Is this being used in an async call that was not returned as a promise to the intent handler? at actions.service.actionssdk.conversation.Conversation.response(Conversation.kt:391) at actions.service.dialogflow.DialogflowConversation.commonPayload(Conv.kt:321) at actions.service.dialogflow.DialogflowConversation.serialize(Conv.kt:366) at actions.service.dialogflow.DialogflowSdk$handler$1.handle(Dialogflow.kt:450) at actions.framework.StandardHandler$DefaultImpls.handle$default(Framework.kt:51) at actions.expected.ServletHandler.handle(BuiltinFrameworks.kt:36) at actions.service.dialogflow.DialogflowSdk$1.handle(Dialogflow.kt:463) at actions.ServiceBaseApp.invoke(Assistant.kt:21) at scott.servlets.FitnessAssistantServlet.simpleDialogFlowExample(FitnessAssistantServlet.kt:30) at scott.servlets.FitnessAssistantServlet.doPost(FitnessAssistantServlet.kt:21)

    My code

    data class MyConversation(val temp: String? = null)
    data class MyArgument(val temp: String? = null, var resultType: String? = null, var userDescision: String? = null)
    
    class FitnessAssistantServlet: HttpServlet() {
        val logger = Logger.getLogger("TestServlet")
    
        @Throws(ServletException::class, IOException::class)
        override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
            val dfApp = dialogflow<UserStorage<Any>, MyConversation, MyArgument>()
            dfApp.frameworks.add(ServletFramework())
            dfApp.intent("test") { conv -> conv.ask("Can you hear me?") }
            dfApp(req, res
        }
    }
    

    It feels like I'm missing some initialization logic somewhere, not sure where though. Thoughts?

    opened by scottlahay 2
  • BasicCard

    BasicCard

    I use a BasicCard in my Java code but the Json serialisation is not correct.
    I have "formattedText$sdk" = "" instead of "formattedText" = "".

    May be "internal var" the cause ?

    data class BasicCard(internal var title: String = "", internal var formattedText: String = "", internal var subtitle: String? = null, internal var image: Image? = null, internal var imageDisplayOptions: ImageDisplays? = null, internal var buttons: MutableList

    opened by nbulteau 0
  • Trigger Followup events via webhook

    Trigger Followup events via webhook

    Hello, how can I trigger an event from my webhook server to Dialogflow? I need that to perform slot fulfillment via webhook.

    This is the reference in Dialogflow docs: https://dialogflow.com/docs/events#invoking_event_from_webhook

    Here is a temporal solution using official Node.js library: https://github.com/actions-on-google/actions-on-google-nodejs/issues/64 But I don't know how to apply that using this library.

    Here is a recent pull request to the official Node.js library adding this feature: https://github.com/actions-on-google/actions-on-google-nodejs/pull/105

    opened by Carleslc 0
Releases(2.0.4)
Owner
Ticketmaster® & Live Nation Entertainment®
Ticketmaster® & Live Nation Entertainment®
GitHub Actions Kotlin DSL

GitHub Actions Kotlin DSL Work in progress! The goal is to be able to describe GH Actions in Kotlin with all its perks, like: workflow( name = "Te

Piotr Krzemiński 271 Dec 26, 2022
A Template for a Github Actions Pipeline for building and publishing Gradle-JVM Applications

github-actions-cd-template-jvm A Template for a Github Actions Pipeline for building and publishing Gradle-JVM Applications It build a executable shad

Raphael Panic 0 Dec 5, 2021
Godot's AdMob Plugin for Android (3.2.2+) using GitHub Actions for CI/CD. Working on Standard and Mono Godot versions.

Godot AdMob Android A Godot's plugin for Android of AdMob. About • Installation • Docs • Downloads About This repository is for a Godot Engine Plugin

Poing Studios 148 Jan 8, 2023
Actions are things that run, with parameters. Serves as a common dependency for a variety of Cepi extensions.

Actions Actions that take in customizable paramaters, an optional target, and do things. Installation Download the jar from Releases OR compile it you

Cepi 1 Jan 9, 2022
📌 replaces mutable tags or branch names by commit shas in your GitHub actions

?? pin-github-actions Using a branch name or tag name as a version for a GitHub action is dangerous as neither branches nor tags are immutable. (See G

Martin Bonnin 10 Jul 21, 2022
Unofficial Android client for dev.to. Open source and free

Dev.to Android by Android Broadcast Unofficial Android client for dev.to Technologies Kotlin Gradle Kotlin DSL Kotlin Coroutines OkHttp + Retrofit kot

Android Broadcast 76 Nov 30, 2022
A fork from Paper and unofficial Airplane continuation for RedeObscurity.

Obscurity A fork from Paper and unofficial Airplane continuation for RedeObscurity. Features Downloads This fork is in a state of development. If you

null 0 Jan 6, 2022
An unofficial Mangadex app using KMM

Mochi An unofficial Mangadex app using KMM. The app uses Mangadex new Public API, which may change at any time. ☢️ !!!Currently in Production. Not int

Michael24884 2 Jan 25, 2022
Kotlin Multiplatform is an SDK for cross-platform mobile development, which enables teams to use the same business logic in both Android and iOS client applications.

Kotlin Multiplatform is an SDK for cross-platform mobile development, which enables teams to use the same business logic in both Android and iOS client applications.

Chris Russell 1 Feb 11, 2022
io.github.jakob.AgonesClient - Kotlin client library for sdk.proto

io.github.jakob.AgonesClient - Kotlin client library for sdk.proto Requires Kotlin 1.3.41 Gradle 4.9 Build First, create the gradle wrapper script: gr

KunJakob 3 Jun 24, 2022
Blog implemented via the Storyblok Kotlin Multiplatform SDK (Android, JVM)

storyblok-mp-SDK-blog ... a showcase of using the Storyblok Kotlin Multiplatform Client to build a blog application (Android, JVM) What's included ??

Mike Penz 5 Sep 28, 2022
Configurable consent SDK for Android

Consent SDK for Android Obtaining explicit user consent regarding the gathering analytics data in an app, or with processing user’s personal data is a

Smartlook 81 Nov 11, 2022
Webtrekk Android SDK V5

Webtrekk Android SDK v5 Site | Docs | Support Webtrekk Android SDK is used to integrate Webtrekk tracking systems with your Android apps. Collect mean

Webtrekk GmbH 13 Apr 26, 2022
Account-lib - A suite of libraries to facilitate the usage of account-sdk

Usage Clone this repository (skip this step if the repo is on your local machine). The default branch is fine. git clone https://github.com/AFBlockcha

null 0 May 24, 2022
The AppMetrica Push SDK is a set of libraries for working with push notifications.

Flutter AppMetrica Push AppMetrica Push SDK — это набор библиотек для работы с push-уведомлениями. Подключив AppMetrica Push SDK, вы можете создать и

Mad Brains 6 Oct 12, 2022
Android sample app for mobile-sdk integration

Dyte Android Sample App An example app in kotlin using the Dyte Mobile Core SDK Explore the docs » View Demo · Report Bug · Request Feature Table of C

Dyte 5 Jul 30, 2022
UserLoc - A API call using Retrofit to obtain list of users details and show on UI in recycler view and google map

UserLoc This uses a API call using Retrofit to obtain list of users details and

Rohit Kumar 0 Jun 22, 2022
🔓 Kotlin version of the popular google/easypermissions wrapper library to simplify basic system permissions logic on Android M or higher.

EasyPermissions-ktx Kotlin version of the popular googlesample/easypermissions wrapper library to simplify basic system permissions logic on Android M

Madalin Valceleanu 326 Dec 23, 2022
AndroidArchitecture - An Implementation of Google Recommended New Android Architecture with Kotlin

Android Architecture An Implementation of Google Recommended New Android Archite

Nayeem Shiddiki Abir 5 Jun 1, 2022