Closed76

既存の amplify appsync 環境を android から使う

tkttkt

既存の物を使う系がでてこなかったので

tkttkt

さっと検索して、既存を使う場合の新しい騎士児が見つからなければ、sdk 直接でやってみる

tkttkt

schema 生成とかはどうやるのか全然わかっていないけど、 amplify 経由でないとできないとかではないはず

tkttkt

https://qiita.com/cantabile_hisa/items/41da410ac8f2d4e6650f
これ見た感じ、既存リソース使ってる
client は作成してるけど

tkttkt
/usr/src# amplify codegen --apiId xxxxxxxxxxxxxxx --envName dev
code generation is not configured. Configure it by running
$amplify codegen add

やっぱりだめそう

tkttkt
# amplify pull --apiId xxxxxxxxxxxxxxxx --envName dev

Pre-pull status:

Current Environment: dev

| Category | Resource name | Operation | Provider plugin |
| -------- | ------------- | --------- | --------------- |

✔ Successfully pulled backend environment dev from the cloud.

Post-pull status:

Current Environment: dev

| Category | Resource name | Operation | Provider plugin |
| -------- | ------------- | --------- | --------------- |

root@74469aeb7e13:/usr/src# amplify update api
? Please select from one of the below mentioned services: GraphQL
No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.
tkttkt

見た感じ、 schema.json と同じディレクトリに xxx.graphql を設置してる
ので、これを参考にやってみる

tkttkt

xxx.graphql

# this is an auto generated file. This will be overwritten

こう書いてあるので、なんか使って生成されてる
検索したらでてくるかな

tkttkt

schema.graphql を aws のページから生成してみる

tkttkt

schema.graphql を aws のページから生成してみる

tkttkt

できrてるのかよくわからんけども、認証してデータ取得まで真似してやってみる

tkttkt

やりたいことがちょっとずれてた

tkttkt

やりたいのは 既存の appsync 環境を新しい client から使うこと、なんだけれど、
既存環境は amplify を使って 作成されている

tkttkt

しらべてみると、amplify pull が使えるらしいので、
amplify pull --appId xxxxxx --envName xxxx
これをやってみた

tkttkt

コマンド実行には成功したけど、
amplify status してみると、
api の部分が deleted になっていて、そのままだと使えないっぽい

tkttkt

amplify pull --appId xxxxxx --envName xxxx --restore
で実行すると、
ApiOperationDelete から No Change に変わった

tkttkt
amplify codegen models

だと、model 生成はできないっぽい

tkttkt
amplify add codegen --apiId xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

これは通った

tkttkt

build しても appsync のモデルクラスが取得できない
amplify codegen models
これが通れば生成される気はするけど、

No AppSync API configured. Please add an API

相変わらずこれ
API の設定はしてるのになぜ

tkttkt

team-provider-info.json を覗いてみたら、apiの記述がない。
どうして

tkttkt

0から amplify で作った appsync のプロジェクトを見ると、
team-provider-info.json には auth, api 両方の記述がない

tkttkt

既存の dynamodb は amplify の cfn ではなく、 cdk で管理されていた

tkttkt
$ amplify update api
? Please select from one of the below mentioned services: GraphQL
The selected resource is not managed using AWS Cloudformation. Please use the AWS AppSync Console to make updates to your API - XXXXXX

cdk を使ってるとだめ?

tkttkt
    1  amplify pull
    2  amplify codegen models
    3  amplify status'
    4  amplify status
    5  amplify pull --restore
    6  amplify codegen
    7  amplify codegen add
    8  amplify codegen
    9  amplify codegen model
   10  amplify codegen models
   11  amplify codegen --help
   12  amplify codegen types
   13  amplify codegen configure
   14  amplify codegen codegen
   15  amplify codegen types

このあたりで、

root@91e605ce4fc7:/usr/src# amplify codegen configure
? Enter the file name pattern of graphql queries, mutations and subscriptions app/src/main/graphql/**/*.graphql
? Enter maximum statement depth [increase from default if your schema is deeply nested] 3
Codegen configured. Remember to run "amplify codegen" to generate your types and statements.
root@91e605ce4fc7:/usr/src# amplify codegen codegen
✔ Downloaded the schema
✔ Generated GraphQL operations successfully and saved at app/src/main/graphql/com/amazonaws/amplify/generated/graphql

これができるようになった

tkttkt

AWSAppSyncClient を使って、 class は生成するな、ということなのか

tkttkt

別プロジェクトに schema.graphql を持っていって、 @model とかを追加して、amplify codegen models して、model のコードを持って返ってきて、実行、としてみたけど、無限のエラーに阻まれて実行できない

tkttkt
Unable to find method 'org.gradle.api.internal.file.DefaultSourceDirectorySet.<init>(Ljava/lang/String;Ljava/lang/String;Lorg/gradle/api/internal/file/FileResolver;Lorg/gradle/api/internal/file/collections/DirectoryFileTreeFactory;)V'
org.gradle.api.internal.file.DefaultSourceDirectorySet.<init>(Ljava/lang/String;Ljava/lang/String;Lorg/gradle/api/internal/file/FileResolver;Lorg/gradle/api/internal/file/collections/DirectoryFileTreeFactory;)V

Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)

Re-download dependencies and sync project (requires network)
The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem.

Stop Gradle build processes (requires restart)
Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.

In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.

そうしたら、ここで謎のエラーに遭遇

tkttkt

記事が書かれたときにはまだできなかったけど、リリースがでてできるようになったみたいな感じかな

tkttkt

readme に従って build.gradle を書いて sync, build したけどエラーは出ない

tkttkt

id 'com.amazonaws.appsync'
もちゃんと通ってる

tkttkt

Next, fetch the schema.json file from the AppSync console and place it alongside the posts.graphql file:
schema.json がいるらしいので、テスト schema で試せない

tkttkt

Next, fetch the schema.json file from the AppSync console and place it alongside the posts.graphql file:

schema.json がいるらしいので、テスト schema で試せない

tkttkt
amplify pull
amplify pull --restore
amplify codegen add

これで schema.json, mutation.graphql, queries.graphql, subscritions.graphql の作成に成功

tkttkt

Now build the project and the generated source files will be available to use within the app. They will not show up in your source directory, but are added in the build path.

build すれば使えるようになるらしい

tkttkt
XXXXXXXXXXXXXXXX\android\app\build\generated\source\appsync\com\amazonaws\amplify\generated\graphql\XXXXXXXXXXXXXX.java:286: {文字化け}
    final @Nullable @Nullable List<XXXXXXXXXX> XXXXXXXXXXXXXXX;

Duplicate annotation. The declaration of 'javax.annotation.Nullable' does not have a valid java.lang.annotation.Repeatable annotation

なぜか @Nullable が二重になった状態で生成されてる

tkttkt

List のところだけ Nullable が二重になってる

tkttkt

navigation components と競合してるっぽい?

tkttkt
ext.kotlin_version = "1.4.21"
ext.nav_version = "2.3.0-alpha04"
    dependencies {
        classpath "com.android.tools.build:gradle:4.1.2"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"

        // AppSync
        classpath 'com.amazonaws:aws-android-sdk-appsync-gradle-plugin:3.1.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
    implementation 'com.squareup.okhttp3:okhttp:4.9.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    // navigation components
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    // AWS AppSync SDK
    implementation 'com.amazonaws:aws-android-sdk-appsync:3.1.0'
}

依存関係メモ

tkttkt
val client = AWSAppSyncClient.builder()
    .context(context)
    .apiKey(BasicAPIKeyAuthProvider(Constants.APPSYNC_API_KEY)) // API Key based authorization
    .region(Constants.APPSYNC_REGION)
    .serverUrl(Constants.APPSYNC_API_URL)
    .build()

これ、 Constants は自分で入れろってことかな

tkttkt

そうっぽい。secrets っぽいのはどこに定義して読んであげれば良いんだろうか

tkttkt

client だから secrets もなにもないか

tkttkt

client を初期化して起動するところまで通った

tkttkt
val client = AWSAppSyncClient.builder()
    .context(this)
    .awsConfiguration(AWSConfiguration(this))
    .build()

ここのところ

tkttkt
package com.example.sample.activity

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.amplify.generated.graphql.ListPostQuery
import com.amazonaws.mobile.config.AWSConfiguration
import com.amazonaws.mobileconnectors.appsync.AWSAppSyncClient
import com.apollographql.apollo.GraphQLCall
import com.apollographql.apollo.api.Response
import com.apollographql.apollo.exception.ApolloException
import com.example.sample.R


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val client = AWSAppSyncClient.builder()
            .context(this)
            .awsConfiguration(AWSConfiguration(this))
            .build()

        val query = ListPostQuery.builder().build()
        val caller = client.query(query)
        caller.enqueue(object : GraphQLCall.Callback<ListPostQuery.Data>() {
            override fun onFailure(e: ApolloException) {
                Log.e("AppSync", "onFailure: fail to fetch", e)
            }

            override fun onResponse(response: Response<ListPostQuery.Data>) {
                Log.d(
                    "AppSync",
                    "onResponse: ${response.data()!!.listPost()!!.items()}"
                )
            }
        })
    }
}

これでデータ取得に成功した
(package 名、model 名はダミー)

tkttkt

ここまでできたので、coroutine もいれてみる

tkttkt
package com.example.sample.activity

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.amplify.generated.graphql.ListPostQuery
import com.amazonaws.mobile.config.AWSConfiguration
import com.amazonaws.mobileconnectors.appsync.AWSAppSyncClient
import com.apollographql.apollo.GraphQLCall
import com.apollographql.apollo.api.Response
import com.apollographql.apollo.exception.ApolloException
import com.example.sample.R
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val client = AWSAppSyncClient.builder()
            .context(this)
            .awsConfiguration(AWSConfiguration(this))
            .build()

        getListPost(client)
    }
    private fun getListPost(client: AWSAppSyncClient) = MainScope().launch(Dispatchers.Main) {
        val result = getListPost(client)
        Log.d("MainActivity", "getListPost: $result")
    }
}

suspend fun getListPost(client: AWSAppSyncClient): List<ListPostQuery.Item> {
    return suspendCoroutine { continuation ->
        val query = ListPostQuery.builder().build()
        val caller = client.query(query)
        caller.enqueue(object : GraphQLCall.Callback<ListPostQuery.Data>() {
            override fun onFailure(e: ApolloException) {
                throw e
            }

            override fun onResponse(response: Response<ListPostQuery.Data>) {
               // ここでこんなに !! して良いものなのかは不安
               val result = response.data()!!.listPost()!!.items()!!
               continuation.resume(result)
            }
        })
    }
}
tkttkt

別PC で作業するときは、改めて configfile をとってくる必要があった

amplify pull --restore
amplify codegen

これで復活した

このスクラップは2021/03/24にクローズされました