20211205のAndroidに関する記事は6件です。

【Android Studio】Gradleでの Jackson の追加方法(Java)

Android Studioを使用したJacksonの使用方法について調べたのですが、実装までに四苦八苦したので、メモを残しておきます。 リポジトリ Jacksonが公開されているページです。 ページ内の取得したいバージョンの「Gradle」の部分をコピーします。 jackson-core https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core jackson-databind https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind jackson-annotations https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations 使用するバージョンの選択 build.gradleに貼り付ける箇所のコピー build.gradle ライブラリの管理はbuild.gradleで行われているので、先ほどコピーした内容をbuild.gradleのdependenciesに追加します。 build.gradle plugins { id 'com.android.application' } android { // 省略 } dependencies { // ここに追加する // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.13.0' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.0' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.13.0' // 以下はデフォルトの内容 implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } 追加した後に再ビルドをすれば、読み込み完了です。 あとは、Javaのコードで、下記の様にjacksonのライブラリをimportすればandroid studioで、Jacksonが使用できるようになります。 (私の場合は、ObjectMapperのreadValueとwriteValueAsStringぐらいしか使わないため、ObjectMapperをimportしています。) import com.fasterxml.jackson.databind.ObjectMapper;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub Actions で .kts ファイルを実行して APK の差分を抽出してみた

この記事は ゆめみ Advent Calendar 2021 の 5 日目の記事です。 はじめに みなさんは、Kotlin のスクリプト言語としての機能を使ったことはありますか? Android アプリの開発で .kts という拡張子のファイルを Gradle で使っているよ!という方は、ちょっぴりいるのかなと思います。 以前は、サポート機能がまだまだ少なく、IDEA のコード補完も効かないなどありましたが、最近、どんどん強化・改善がされ、少しずつ使いやすくなってきました。 GitHub Actions に Kotlin がプリインストールされていて、せっかくなので APK の差分を抽出してみました 成果物 ※ GitHub Marketplace へも近日リリース予定です 実際の動作 スクリプト言語としての機能について さよなら Gradle Gradle ファイルは必要ありません ライブラリを使いたいときは? // ライブラリをインストールしてくるリポジトリを記載 @file:Repository("https://repo1.maven.org/maven2/") // 使用するライブラリを記載 @file:DependsOn("eu.jrie.jetbrains:kotlin-shell-core:0.2.1") // ライブラリで使用するものを記載 import eu.jrie.jetbrains.kotlinshell.shell.* ファイルの数が増えなくて快適です シェルコマンドを実行したい場合はどうするの? 公式でのドキュメントは見つかりませんでしたが、以下のライブラリを使って解決しました 書き方はいろいろありますが、こんな感じで書けます shell { "echo hello"() } shell { val echo = systemProcess { cmd { "echo" withArg "hello" } } echo() } shell { val echo = "echo hello".process() echo() } ライブラリの作成者に感謝 APK の差分の抽出 Android SDK のコマンドラインツールに含まれている apkanalyzer を利用します GitHub Actions には Android SDK のコマンドラインツールもプリインストールされているため、自分でインストールする必要がないのはいいですね Kotlin の恩恵 apkanalyzer の結果をゴニョゴニョしたい時にとても恩恵を感じました。 以下のコードは「タブ文字を "|" に変換して、 差分が~Bと表示されているものは除外する」という処理です。 これをシェルスクリプトでやろうとするとけっこう大変ですよね (日常的にシェルスクリプトを触っている方であればそうでもないのでしょうか。。) val compare = result("apkanalyzer -h apk compare --different-only $baseApkPath $targetApkPath") .replace("\t", "|") .split("\n") .filter { !it.contains("""\dB.+$""".toRegex()) } .joinToString("\n") おわりに Kotlin のスクリプト言語機能を活用して、とても快適に GitHub Actions を開発することができました。 今後もどんどん活用していこうと思います ぜひ、みなさんも Kotlin のスクリプト言語機能をご活用ください! 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHubのmavenにAndroidのライブラリをリリースしてみる

はじめに 株式会社ピー・アール・オーのアドベントカレンダー5日目です。 前回はiOS用のフレームワークをCocoaPodsに公開する手順を書きました、今回はAndroid用ライブラリをmavenに公開してみます。 今回はGitHubのpackages機能を利用してライブラリをリリースします。 事前準備 Android Studioをインストールする GitHub上にAndroidライブラリ用のリポジトリを用意する maven-publishプラグインを有効する 今回はAndroid Studioが提供するMaven Publish Pluginを利用してライブラリをリリースします。まずはライブラリモジュールのbuild.gradleにmaven-publishを有効します。 plugins { id 'maven-publish' } リリースするライブラリの情報を定義する 次は、同じライブラリモジュールのbuild.gradleに下記のリリースするライブラリの情報を追加します。 下記のコードはBuild Variantがrelease時のAARライブラリを作ってリリースします。 afterEvaluate { publishing { publications { // Creates a Maven publication called "release". release(MavenPublication) { // Applies the component for the release build variant. from components.release // You can then customize attributes of the publication as shown below. groupId = 'com.lxlgarnett.colorpicker' artifactId = 'color-picker' version = '1.0.0' } } } groupId: ユニークなID、今回はライブラリのパッケージ名を利用する artifactId: 公開するライブラリ名 version: 公開するライブラリのバージョン GitHubのmavenリポジトリを追加する リリース情報を追加したら、次は公開するmavenリポジトリの定義を追加します。 afterEvaluateのpublishingに下記のコードを追加します。 repositories { maven { name = 'GitHubPackages' url = uri("https://maven.pkg.github.com/lxlgarnett/color-picker-android") } } GitHub用アクセストークンを発行する GitHubトークン画面にアクセスし、新しいトークンを生成します。 発行したトークンに必ずwrite:packagesにチェックを入れてください。 GitHub認証情報を追加 次は発行したトークン情報をbuild.gradleに追加します。 credentials { username = [You GitHub Username] password = [Generated GitHub Token] } ※ セキュリティのため、発行したトークン情報はGitHubにコミットしちゃいけないため、ローカルの.propertiesに保存したほうが良いです。 完成版のコード afterEvaluate { publishing { publications { // Creates a Maven publication called "release". release(MavenPublication) { // Applies the component for the release build variant. from components.release // You can then customize attributes of the publication as shown below. groupId = 'com.lxlgarnett.colorpicker' artifactId = 'color-picker' version = '1.0.0' } } repositories { maven { name = 'GitHubPackages' url = uri("https://maven.pkg.github.com/lxlgarnett/color-picker-android") credentials { username = [Your GitHub Username] password = [Generated GitHub Token] } } } } } ライブラリを公開する 最後はプロジェクトをsyncし、下記のコマンドでライブラリを公開します。 ./gradlew publish 公開したライブラリを使ってみる それでは、実際公開したライブラリはどう使うでしょう? mavenリポジトリ情報を追加する まずは利用するプロジェクト側のプロジェクト用のbuild.gradleにGitHubのmavenリポジトリ情報を追加します。 allprojects { repositories { google() mavenCentral() maven { name = 'ColorPickerGitHubPackages' url = uri('https://maven.pkg.github.com/lxlgarnett/color-picker-android') credentials { username [Your GitHub Username] password [Your GitHub Token] } } } } ※ GitHubのmavenリポジトリはPublicなリポジトリでも、認証情報が必要となります。 Dependency情報を追記する 次はアプリモジュール側のbuild.gradleにライブラリのDependency情報を追加します。追加が終わった後、プロジェクトをsyncし、ビルドすればOKです。 implementation 'com.lxlgarnett.colorpicker:color-picker:1.0.0' 参考サイト Android Studio Maven Publish plugin
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

何故Modifierは最初のデフォルト引数でないといけないのか

Jetpack Composeでコード書いていると、次のような警告を見かけることがあります。 Modifier parameter should be the first optional parameter Modifierは最初のデフォルト引数であるべき、という話ですね。 例えば次のようなコードを書いた場合に上記の警告が出ます。 @Composable fun SampleComposable( param: Boolean, optionalParam: String = "First optional param", modifier: Modifier = Modifier, ) そしてこの方針はModifierのドキュメントにも書かれています。 It should appear as the first optional parameter in the parameter list; after all required parameters (except for trailing lambda parameters) but before any other parameters with default values. しかし何故Modifierは最初のデフォルト引数でないといけないのでしょうか? 先に結論 ガイドライン上、そう定められているため APIの一貫性を保つため 詳細 警告を出しているLintの実装は以下です。 このコミットログを追うと "for consistency with Compose guidelines" という記述が確認できます。 https://android-review.googlesource.com/c/platform/frameworks/support/+/1502816 そしてComposeのAPIガイドラインには次のような記述があります。 Modifiers occupy the first optional parameter slot to set a consistent expectation for developers that they can always provide a modifier as the final positional parameter to an element call for any given element's common case. Modifierを常に最初のデフォルト引数にしていくおくと、開発者は最後にmodifierを書けばいいと期待してコードを書けるらしいです。どういうことでしょう? 例えば、TextやButtonが次のように実装されていたとします。 fun Text( text: String, modifier: Modifier = Modifier, // 1st optional parameter color: Color = Color.Unspecified ) @Composable fun Button( onClick: () -> Unit, enabled: Boolean = true, modifier: Modifier = Modifier, // 2nd optional parameter ) これらをModifierを指定して呼び出すと次のようになります。 Text("sample text", Modifier.padding(8.dp)) Button({ /* onClick */ }, modifier = Modifier.padding(8.dp)) Textがシンプルに書けた一方、ButtonのModifierは2番目のデフォルト引数であるため、modifier=の名前付き引数にする必要が出てしまいました。 このようにModifier引数の順番が不規則であると、Composable毎に引数の順番を意識して書く必要が出てしまいます。Modifierが各所で使われる仕組みであることを考えると、これは良くないでしょう。 従って、一貫性を保つためにModifierは最初のデフォルト引数であるべき、としているわけです。 これを守ることでComposableを書くときには必須のパラメータを記述して、最後にModifierを書けばいい、という共通認識でコードが書くことができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Material 3で大きく変わったTopAppBarをJetpack Composeで実装してみる

本記事は Android Advent Calendar 2021 の 6 日目の記事です。 Material 3 で TopAppBar のデザインや挙動が変わりました。 Jetpack Compose の Material3 対応版である androidx.compose.material3 を使用してガイドラインに合わせた実装例をいくつか見ていこうと思います。 ※androidx.compose.material3 は 1.0.0-beta02 時点の内容なので、ライブラリの更新で内容が変わる可能性もあります。 TopAppBar のパターン Material 3 では TopAppBar に以下の 4 つのパターンがあります。 Center-aligned Small Medium Large それぞれの実装例を見ていきましょう。 Center-aligned CenterAlignedTopAppBar の Composable 関数を使います。 @Composable fun CenterAlignedTopAppBar( title: (@Composable () -> Unit)?, modifier: Modifier? = Modifier, navigationIcon: (@Composable () -> Unit)? = {}, actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {}, colors: TopAppBarColors? = TopAppBarDefaults.centerAlignedTopAppBarColors(), scrollBehavior: TopAppBarScrollBehavior? = null ): Unit CenterAlignedTopAppBar をそのまま使用した場合 Surface の色がそのまま適用されます。 Material 3 の TopAppBar はコンテンツのスクロールに合わせて elevation が変わる Lift On Scroll を適用する必要があり、Jetpack Compose では TopAppBarDefaults.pinnedScrollBehavior を使用して実装します。 @Composable fun ExampleScreen() { val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { CenterAlignedTopAppBar( title = { Text(text = "Title") }, navigationIcon = { BackIconButton { } }, scrollBehavior = scrollBehavior ) } ) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = it ) { ... } } } Small SmallTopAppBar の Composable 関数を使います。 @Composable fun SmallTopAppBar( title: (@Composable () -> Unit)?, modifier: Modifier? = Modifier, navigationIcon: (@Composable () -> Unit)? = {}, actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {}, colors: TopAppBarColors? = TopAppBarDefaults.smallTopAppBarColors(), scrollBehavior: TopAppBarScrollBehavior? = null ): Unit CenterAlignedTopAppBar と同じく、スクロールに合わせて TopAppBar の色を変えるには TopAppBarDefaults.pinnedScrollBehavior を使用して以下のように実装する必要があります。 @Composable fun ExampleScreen() { val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { SmallTopAppBar( title = { Text(text = "Title") }, navigationIcon = { BackIconButton { } }, scrollBehavior = scrollBehavior ) } ) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = it ) { ... } } } また、TopAppBarDefaults.enterAlwaysScrollBehavior を使うと上にスクロールすると TopAppBar を隠し下にスクロールさせると TopAppBar を表示させる挙動にすることもできます。 Medium MediumTopAppBar の Composable 関数を使います。 @Composable fun MediumTopAppBar( title: (@Composable () -> Unit)?, modifier: Modifier? = Modifier, navigationIcon: (@Composable () -> Unit)? = {}, actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {}, colors: TopAppBarColors? = TopAppBarDefaults.mediumTopAppBarColors(), scrollBehavior: TopAppBarScrollBehavior? = null ): Unit Medium の TopAppBar は上にスクロールすると折り畳まれる必要があります。 また Medium の TopAppBar はスクロールが一番上に到達するまで折り畳まれている必要があるので、TopAppBarDefaults.enterAlwaysScrollBehavior ではなく TopAppBarDefaults.exitUntilCollapsedScrollBehavior を使用することで一番上にスクロールするまで折り畳まれた状態にすることができます。 @Composable fun ExampleScreen() { val decayAnimationSpec = rememberSplineBasedDecay<Float>() val scrollBehavior = remember(decayAnimationSpec) { TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec) } Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { MediumTopAppBar( title = { Text(text = "Title") }, navigationIcon = { BackIconButton { } }, scrollBehavior = scrollBehavior ) } ) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = it ) { ... } } } Large LargeTopAppBar の Composable 関数を使います。 @Composable fun LargeTopAppBar( title: (@Composable () -> Unit)?, modifier: Modifier? = Modifier, navigationIcon: (@Composable () -> Unit)? = {}, actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {}, colors: TopAppBarColors? = TopAppBarDefaults.largeTopAppBarColors(), scrollBehavior: TopAppBarScrollBehavior? = null ): Unit Medium と同じくスクロールした時に折り畳まれているようにするため TopAppBarDefaults.exitUntilCollapsedScrollBehavior を実装します。 @Composable fun ExampleScreen() { val decayAnimationSpec = rememberSplineBasedDecay<Float>() val scrollBehavior = remember(decayAnimationSpec) { TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec) } Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { LargeTopAppBar( title = { Text(text = "Title") }, navigationIcon = { BackIconButton { } }, scrollBehavior = scrollBehavior ) } ) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = it ) { ... } } } Material 3 では TopAppBar にいくつか種類が登場し、Jetpack Compose では Lift On Scroll のために少しばかり実装の必要があります。 参考 https://m3.material.io/components/top-app-bar https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android】 Jetpack Composeでドラッグ&ドロップの並び替えを実現する 〜ライブラリに頼って〜

この記事は、and factory.inc Advent Calendar 2021の 5日目 の記事です。 昨日は @y-okudera さんの「 データの暗号化・復号とSwiftでの実装の仕方について改めて調べてみた 」でした! ドラッグ&ドロップで並び替えしたい リスト表示において、アイテムを長押しするとドラッグ&ドロップで並び替えができる、というのは結構あるあるな機能ではないでしょうか? RecyclerViewではItemTouchHelperを使うことで、ドラッグ&ドロップでの並び替えを実装することができました。 しかしながら、Jetpack Composeにおいては、現状ドラッグ&ドロップはサポートされておりません。 一応ロードマップには「ドラッグ&ドロップのサポート」が記載されているので、今後公式にサポートされるものと思われます。 「公式にサポートされるまで待てないよ…!」という欲求に駆られたため、今回はライブラリの力に頼って ドラッグ&ドロップでの並び替えを実現してみたいと思います。 aclassen/ComposeReorderable LazyList ( LazyColumn、LazyRow )のドラッグ&ドロップでの並び替えを可能にするライブラリです。 こちらのライブラリの使い方を説明していきたいと思います。 Before シンプルな LazyColumn を使った画面に、 ComposeReorderable を用いたドラッグ&ドロップでの並び替えを追加していくことを想定します。 対応前のコード↓ Scaffold( topBar = { TopAppBar(title = { Text("Sample") }) } ) { val data = remember { mutableStateOf(List(100) { "$it" }) } LazyColumn { items(data.value) { item -> Box( modifier = Modifier .fillMaxWidth() .clickable {} .padding(40.dp), ) { Text(item) } Divider(thickness = 1.dp) } } } 画面としては↓のような感じです。 1. dependenciesへの追加 dependencies に追加します。記事作成時では 0.7.4 が最新版でした。 + implementation "org.burnoutcrew.composereorderable:reorderable:0.7.4" 2. LazyColumnへ設定追加 ① rememberReorderState() を呼び出し ReorderableState を作成します。 ② 作成した ReorderableState の listState を、 LazyColumn の state に指定します。 ③ ComposeReorderable の拡張である reorderable Modifierも設定します。 - LazyColumn { + val reorderState = rememberReorderState() // ① + + LazyColumn( + state = reorderState.listState, // ② + modifier = Modifier // ③ + .reorderable( + state = reorderState, + onMove = { from, to -> /* TODO */ }, + ), + ) { 3. リストのアイテムへの設定追加 リストの各アイテムの Modifier へ設定を追加します。 ① 並び替え可能なアイテムであることを示すために、detectReorder(state) or detectReorderAfterLongPress(state) を指定します。 detectReorderAfterLongPress(state) の場合は、長押しで並び替えが起きるようになるので、今回はこちらを指定します。 ② draggedItem の指定も追加します。 引数の offset には reorderState.offsetByKey or reorderState.offsetByIndex を使って指定します。 ) { - items(data.value) { item -> + itemsIndexed(data.value) { index, item -> Box( modifier = Modifier .fillMaxWidth() .clickable { /**/ } + .detectReorderAfterLongPress(reorderState) // ① + .draggedItem(reorderState.offsetByIndex(index)) // ② .padding(40.dp), ) { Text(item) 一応この時点で、ドラッグ&ドロップは動くようになっています…! ただ、データ自体が変わっていないため、ドラッグしているアイテムがおかしなことになっているので、2で /* TODO */ にしていた onMove の処理を実装します。 4. データの更新実装 ドラッグ&ドロップでアイテムを動かし、他のアイテムと切り替わるタイミングで onMove が呼ばれるので、そのタイミングでデータの更新をしてあげる必要があります。 ※ move は ComposeReorderable に入っている拡張関数です。 - onMove = { from, to -> }, + onMove = { from, to -> + data.value = data.value.toMutableList().apply { move(from.index, to.index) } + }, 以上の工程で、ドラッグ&ドロップによる並び替えを実装することができました? After Beforeの対比としてAfterのコードも載せておきます。 Scaffold( topBar = { TopAppBar(title = { Text("Sample") }) } ) { val data = remember { mutableStateOf(List(100) { "$it" }) } val reorderState = rememberReorderState() LazyColumn( state = reorderState.listState, modifier = Modifier .reorderable( state = reorderState, onMove = { from, to -> data.value = data.value.toMutableList().apply { move(from.index, to.index) } }, ), ) { itemsIndexed(data.value) { index, item -> Box( modifier = Modifier .fillMaxWidth() .clickable {} .detectReorder(reorderState) .draggedItem(reorderState.offsetByIndex(index)) .padding(40.dp), ) { Text(item) } Divider(thickness = 1.dp) } } } 終わりに (ただのライブラリの使い方の説明記事になってしまいましたが…) Jetpack Composeでドラッグ&ドロップの並び替えを実現することができました。 「公式にサポートされるまで待てないよ…!」という方の参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む