Let's EncryptでSSLHandshakeException
環境
Pixel 4a(Android 11)
エラー
HTTP FAILED: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
状況
解決
Chain of Trust - Let's Encrypt から必要な証明書をダウンロードして raw ディレクトリに保存し、OkHttpやWebViewに追加する。
OkHttp
build.gradleに以下を追加
implementation "com.squareup.okhttp3:okhttp-tls:$okhttp_version"
okhttp/okhttp-tls at master · square/okhttp · GitHub
保存した証明書を追加する。
private fun buildOkHttp(): OkHttpClient { val x1Certificates = context.resources.openRawResource(R.raw.isrg_root_x1).reader() .use(InputStreamReader::readText).decodeCertificatePem() val x2Certificates = context.resources.openRawResource(R.raw.isrg_root_x2).reader() .use(InputStreamReader::readText).decodeCertificatePem() val r3Certificates = context.resources.openRawResource(R.raw.lets_encrypt_r3).reader() .use(InputStreamReader::readText).decodeCertificatePem() val certificates = HandshakeCertificates.Builder() .addTrustedCertificate(x1Certificates) .addTrustedCertificate(x2Certificates) .addTrustedCertificate(r3Certificates) .build() return OkHttpClient .Builder() .sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager) .build() }
okhttp-tlsのサンプルはこちら
okhttp/CustomTrust.kt at master · square/okhttp · GitHub
WebView
xml/network_security_config.xml として以下のファイルを作成。
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" > <trust-anchors> <certificates src="@raw/isrg_root_x1" /> <certificates src="@raw/isrg_root_x2" /> <certificates src="@raw/lets_encrypt_r3" /> <certificates src="system" /> </trust-anchors> </base-config> </network-security-config>
AndroidManifest.xmlに以下の記述を追加
<manifest...> <application ... android:networkSecurityConfig="@xml/network_security_config" ... </application> </manifest>
参考

- 作者:Rescorla,Eric,齋藤 孝道,貞, 古森,利之, 鬼頭
- 発売日: 2003/11/01
- メディア: 単行本
プロローグにはコンテンツを指定できません。
環境
Android Studio 4.1.2
Android Gradle Plugin 4.1.2
エラーメッセージ
FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:extractDeepLinksDevDebug'. > org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; プロローグにはコンテンツを指定できません。
状況
AndroidStudioでビルドすると上記エラーとなった。./gradlew app:assembleDebug でも同様。
直前の成功ビルドからの差分はなく、AndroidStudio上でbuild variantを切り替えたタイミングで突然発症し、initial commit 付近まで戻しても同様のエラーが出るようになった。
以下試すも効果なし。
.idea/削除app/build/削除~/.gradle/caches削除- Invalidate Caches / Restart
解決
リソースのnavigationディレクトリを作り直したら何故か症状がでなくなった。
main/res/navigation/ ディレクトリを削除して、resディレクトリの右クリックから [New] -> [Android Resource File] でナビゲーションのxmlを作り直して復旧。
git上の差分は特になし。
ConstraintLayoutで垂直方向で中央に集める
環境
Android Studio 4.1.2
やりたいこと
ConstraintLayoutでViewを上下真ん中に集めたい。
これを

こうしたい

やったこと
いじる前のレイアウトはこちら。
<?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" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button2" /> </androidx.constraintlayout.widget.ConstraintLayout>
GUIでやる場合
- 全部選ぶ

- 右クリックメニューから [Chains] -> [Create Vertical Chain]

するとこんな感じになる

- 右クリックメニューから[Chains] -> [Vertical Chain Style] -> [packed]

すると真ん中に寄る

手動でやる場合
- チェーンな関係にする
layout_constraintVertical_chainStyleにpackedを指定する
チェーンとは、『双方向の位置制約を設定して、相互にリンクさせたビューのグループ』のこと。(参照:ConstraintLayout でレスポンシブ UI を作成する)
button1の layout_constraintBottom_toTopOf にbutton2を、button2の layout_constraintTop_toBottomOf にbutton1を指定した関係がチェーンとなる。
今回の場合Viewが3つあるので、button <-> button1と、button1 <-> button2 をそれぞれチェーンにする必要がある。
チェーンに対してスタイルを指定することができる。ここに packed を指定することで期待する中央寄せの状態になる。
app:layout_constraintVertical_chainStyle="packed"
結果
垂直方向で中央に集まった状態のレイアウトはこちら。
<?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" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" app:layout_constraintBottom_toTopOf="@+id/button2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" app:layout_constraintBottom_toTopOf="@+id/button3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button2" /> </androidx.constraintlayout.widget.ConstraintLayout>
参考

Android Layout Cookbook アプリの価値を高める開発テクニック
- 作者:あんざい ゆき
- 発売日: 2011/03/11
- メディア: 単行本(ソフトカバー)
AndroidStudioでrubyのシンタックスハイライト
環境
Android Studio 4.0
やりたいこと
AndroidStudioでRubyのソースコードを見やすくしたい。

やったこと
- TextMate Bundles プラグインをインストール

- https://github.com/textmate/ruby.tmbundle/ を任意の場所にclone
- Preferences -> Editor -> TextMate の + ボタンから、cloneした
ruby.tmbundleディレクトリを選択
結果
参考
https://youtrack.jetbrains.com/issue/OC-13269
XcodeでCreated byの名前を変えるためにやったこと
環境
Xcode 11.6 (11E708)
macOS 10.15.4(19E287)
やりたいこと
Xcodeでファイルを新規作成したときに自動で挿入されるコメント内のユーザー名を変更したい。
// // ContentView.swift // Sample // // Created by (ここに表示される名前) on 2020/08/15 // Copyright © 2020 ergo. All rights reserved. //
やったこと
~/Library/Developer/Xcode/UserData/ に 以下の内容で IDETemplateMacros.plist というファイルを作成する。
(ここに表示される名前) の部分に任意の名前を入れればOK。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FILEHEADER</key>
<string>
// ___FILENAME___
// ___TARGETNAME___
//
// Created by (ここに表示される名前) on ___DATE___
// ___COPYRIGHT___
//</string>
</dict>
</plist>
参考
Kotlin + dokka でマルチモジュールのJavadocを生成
環境
Android Studio 3.5
macOS 10.14.4
kotlin 1.3.50
対象のモジュール構成
以下のような構成のプロジェクトを想定し、lib1とlib2のJavadocをまとめて生成する。
| モジュール | 説明 |
|---|---|
| app | lib1とlib2に依存したアプリモジュール |
| lib1 | Javadoc生成対象のライブラリモジュール |
| lib2 | Javadoc生成対象のライブラリモジュール |
dokka導入
GitHub - Kotlin/dokka: Documentation Engine for Kotlin を参考に、プロジェクトのルートのbuild.gradleに以下を記述する。
buildscript {
ext.dokka_version = '0.9.18'
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${dokka_version}"
}
}
ドキュメント用のモジュールを追加
Javadoc生成対象のソースコードをまとめ上げるモジュールを作成して、sourceSetsにドキュメント生成対象のコードを追加する。
main.java.srdDir にソースセットを追加すると、appモジュールからライブラリのコードが正しく解決できなくなってしまったので、ドキュメント用のBuildTypeを定義してそこに追加するのがよさそう(以下の例では docs というBuildTypeを定義している)。
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'org.jetbrains.dokka-android'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
// ドキュメント用のビルドタイプを定義する。これをしないとappモジュールからライブラリのコードをうまく解決できない。
docs {}
}
sourceSets {
// ドキュメント生成対象のコードをソースセットに追加する
docs.java.srcDirs += '../lib1/src/main/java'
docs.java.srcDirs += '../lib2/src/main/java'
}
}
dokka {
outputFormat = 'javadoc'
sourceDirs = files('src/main')
outputDirectory = "$project.rootDir/docs"
linkMapping {
// Unix based directory relative path to the root of the project (where you execute gradle respectively).
dir = "src/main/kotlin" // or simply "./"
// URL showing where the source code can be accessed through the web browser
url = "https://github.com/cy6erGn0m/vertx3-lang-kotlin/blob/master/src/main/kotlin"
//remove src/main/kotlin if you use "./" above
// Suffix which is used to append the line number to the URL. Use #L for GitHub
suffix = "#L"
}
}
Javadoc生成
./gradlew dokka
サンプルコード
https://github.com/ergooo/DokkaMultiModuleSample
Javadoc生成結果
https://ergooo.github.io/DokkaMultiModuleSample/
参考

- 作者: Dmitry Jemerov,Svetlana Isakova,長澤太郎,藤原聖,山本純平,yy_yank
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/10/31
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
AWSLambdaClient#invokeでTooManyRequestsException: Rate Exceeded.
環境
やろうとしたこと
以下のようなコードで長めのAWS LambdaをJavaから実行しようとした。
val invokeRequest = InvokeRequest() .withFunctionName(FUNCTION_NAME) .withPayload("適当なpayload") .withInvocationType(InvocationType.RequestResponse) val lambdaClient = AWSLambdaClientBuilder.standard() .withRegion(REGION) .withCredentials(AWSStaticCredentialsProvider(credentials)).build() val invokeResult = lambdaClient.invoke(invokeRequest) // ここでTooManyRequestsException
エラー
Exception in thread "main" com.amazonaws.services.lambda.model.TooManyRequestsException: Rate Exceeded. (Service: AWSLambda; Status Code: 429; Error Code: TooManyRequestsException; Request ID: XXXXXXXXXXXX)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1701)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1356)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1102)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:759)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:733)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:715)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:675)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:657)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:521)
at com.amazonaws.services.lambda.AWSLambdaClient.doInvoke(AWSLambdaClient.java:3137)
at com.amazonaws.services.lambda.AWSLambdaClient.invoke(AWSLambdaClient.java:3104)
at com.amazonaws.services.lambda.AWSLambdaClient.invoke(AWSLambdaClient.java:3093)
at com.amazonaws.services.lambda.AWSLambdaClient.executeInvoke(AWSLambdaClient.java:1744)
at com.amazonaws.services.lambda.AWSLambdaClient.invoke(AWSLambdaClient.java:1716)
解決
AWSLambdaClientBuilder#withClientConfiguration()でタイムアウトを設定
val invokeRequest = InvokeRequest() .withFunctionName(FUNCTION_NAME) .withPayload("適当なpayload") .withInvocationType(InvocationType.RequestResponse) val lambdaClient = AWSLambdaClientBuilder.standard() .withRegion(REGION) // ↓これを追加 .withClientConfiguration(ClientConfigurationFactory().config.withSocketTimeout(TIMEOUT)) .withCredentials(AWSStaticCredentialsProvider(credentials)).build() val invokeResult = lambdaClient.invoke(invokeRequest)
InvokeRequest#withSdkClientExecutionTimeout() とかInvokeRequest#withSdkRequestTimeout()とかそれっぽいのもあったけどそれらは反映されなかった。。

実践AWS Lambda ~「サーバレス」を実現する新しいアプリケーションのプラットフォーム~
- 作者: 西谷圭介
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/06/09
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る



