Android App Bundle (Androidアプリバンドル) -aabからapkを作成してサイズ削減量をチェックしてみる

mobile-ffmpegを組み込んだAndroidアプリをリリースしたけどサイズが大きい。。
full-gplからminにするだけで20MB以上は削減できるけど
それでもAPKファイルは35MB近くある。。

Android App Bundleでリソースファイルだけでも小さくできないか試してみました。

アプリバンドルの作成

Android StudioのビルドからAPKではなく、バンドルを選んで出力するだけ。

アプリバンドルから端末向けのAPK生成

bundletoolをダウンロード

https://github.com/google/bundletool
Bundletool is a tool to manipulate Android App Bundles.
The Android App Bundle is a new format for publishing Android apps in app distribution stores such as Google Play.

”–connected-device”でadbで接続中の端末に向けたApkができるらしい。


 java -jar bundletool-all-0.9.0.jar build-apks \
 --bundle=/ path to /app.aab \
 --output=/ path to /myapp.apks \
 --ks=~/.android/debug.keystore \
 --ks-pass=pass:android \
 --ks-key-alias=androiddebugkey \
 --key-pass=pass:android \
 --connected-device

自分の環境では35MB->30MBだったので効果はあった。

既存のAPK配信アプリをバンドルへ移行

upload_cerとdeployment_certは表示されてるので、ローカルのkeystoreとPEPKで紐づけるのか
PEPKツール(Play Encrypt Private Key)が必要らしいけどダウンロードボタンどこ?。。
あとでにします。

jad(Linux on Intel platform)でNo such file or directoryが出たのでstatically linkedにしたら動いた

https://varaneckas.com/jad/

ubuntuの環境でわかりにくかったエラー
ソースを無くしたので、Classファイルをjavaファイルに戻そうと
jadを実行しようとしたら、”jad: No such file or directory”??


root@doroidpanic-ubuntu:/opt/Jad1.5.8e/jad# jad
-bash: /opt/Jad1.5.8e/jad: No such file or directory
root@doroidpanic-ubuntu:/opt/Jad1.5.8e/#
root@doroidpanic-ubuntu:/opt/Jad1.5.8e/# ls -la
-rwxrwxr-x 1 root root 961596 Aug  6  2001 jad

ダウンロードしたのは
「Jad 1.5.8e for Linux on Intel platform (214917 bytes)」でLinux向けは
「Jad 1.5.8e for Linux (statically linked) (389972 bytes)」もあるけど

take this version if the one above crashes or displays the “seek error” message.

とあるので、.soがないとか言ってなからどうなんだろうと思いながら
(statically linked)に変更したら、動いた。。。


root@doroidpanic-ubuntu:/opt/Jad1.5.8e/jad# jad
Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov (kpdus@yahoo.com).
Usage:    jad [option(s)] 
Options: -a       - generate JVM instructions as comments (annotate)
         -af      - output fully qualified names when annotating
         -b       - generate redundant braces (braces)
         -clear   - clear all prefixes, including the default ones

ちなみにVPSはintelだったのでいいと思ったんだけどな。。


root@doroidpanic-ubuntu:$cat /proc/cpuinfo
vendor_id	: GenuineIntel
cpu family	: 6
model		: 62
model name	: Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz

iOSでAdMob No ad to show.がでるけど追跡型広告を制限をOFFで解決した

iOSでAdMobを設定してリリース前にTestDeviceID設定してないiPhoneでバナーなどが表示されないことがよくある。
AdmobのAppIDとコードはあってるけど
こんなエラー。。


Banner error Request Error: No ad to show.

コード作成してすぐはNGとか0ptの枠に表示してるとかStackOverflowにはあるけど
自分の場合は、iOS側のプライバシー設定の「追跡型広告を制限」をOFFにすると広告が表示される。
ということはたまたま金額などの関係で追尾広告だけが配信されてるってことなのかな?

EXC_BAD_ACCESSが出たけど、よく見たら凡ミスだった

EXC_BAD_ACCESSはlogに書き込むデータを取得しているところだった
さっきまで動いてたんだけどな。。


formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
return formatter.string(from: date)

let fileName = filePath.components(separatedBy: "/").last

と思ったら、SwiftBeaverから切り替えたときについでにprint()がプロジェクトにところどころ残ってたので調子に乗ってLoggerに置き換えしたら、logger自身のアウトプットのprintもloggerメソッドに切り替えたので無限ループしてEXC_BAD_ACCESSでした。

UIStackViewはsetBackgroundColorで背景色変更が出来なかった

背景を変えようとsetBackgroundColorしたけど
エラーは出ないけど、UIStackViewってsetBackgroundColorでは色変わらないらしい。


こんな感じではダメだった。XCodeサジェストだすなよ。。
UIStackView.setBackgroundColor( UI.Color )

how to change the background color of UIStackView?
https://stackoverflow.com/questions/34868344/how-to-change-the-background-color-of-uistackview

Android 9 (Pie)でandroid.view.InflateException: Binary XML file lineが発生、Android8などでは動作するがPieでInflateExceptionエラー

リリースしたアプリがAndroid9でクラッシュしてしまうらしい。
手元にAndroid9(Pie)がないのでエミュレーターで確認すると、確かにMainActivityが起動できていない。
ログを見ると、android.view.InflateExceptionが発生していた。
Android8とかでは何機種試したけど、普通に動作するんだけどな。。


Process: com.doroidpanic.test, PID: 28843
    android.view.InflateException: Binary XML file line #28: Binary XML file line #28: Error inflating class TextView
    Caused by: android.view.InflateException: Binary XML file line #28: Error inflating class TextView
    Caused by: java.lang.NumberFormatException: For input string: "bold"

「java.lang.NumberFormatException: For input string: “bold”」???
ログに出てるXMLを追ってくと、確かにTextViewに行き着いて
そのTextViewにはtextFontWeightが指定してある。


android:textFontWeight="bold"

AndroidStudioが「Attribute textFontWeight is only used in API level 28 and higher r (current min is 21)」と言ってるけど、非推奨とかじゃないしな。。

この書き方も同じエラーで落ちる。


android:textStyle="bold"

adMobのリワード広告 – RewardedVideoAd.isLoadedでも真っ黒画面で広告がでない

事前にロードするリワードだと仕方がないかもしれないけど
admobの管理画面で表示と読込の乖離が気になってしまうので
すこしでもと、リワードを表示させるアクティビティを再描画する際、すでに広告を読み込んでいれば、loadAdしないようにしてみましたが、onResume後のチェックでisLoadedとなっても、.show()で真っ黒のリワードアクティビティがスタートしてしまった。。


@Override
protected void onResume() {
    if( rewardedVideoAd != null ) {
        rewardedVideoAd.resume( this );
    }
    super.onResume();
    loadRewardedVideoAd();
}

void loadRewardedVideoAd(){
    if( rewardedVideoAd.isLoaded() ){
        reward.setClickable( true );
        reward.setEnabled( true );
        // onResume後にここに入ってボタンで開始しても.show()で真っ黒
    }else{
        rewardedVideoAd.loadAd( getString( R.string.reword_ad_code ),
                new AdRequest.Builder().addTestDevice( getResources().getString( R.string.test_device_id ) ).build() );
    }
}

ログをみるとonRewardedVideoStartedは呼ばれているので
admobは表示されてるみたいですが、コンテンツが表示されない。。
onResume後はisLoaded()がtrueでも再度loadAdすればもちろん問題ないけど、どうなんだろう。。

firebase-core:16.0.6をアップデートしたらorg.gradle.api.resources.ResourceException: Could not get resourceが発生

firebase-coreをアップデートしたらorg.gradle.api.resources.ResourceException: Could not get resourceが発生


- implementation 'com.google.firebase:firebase-core:16.0.6'
+ implementation 'com.google.firebase:firebase-core:16.0.7'

‘https://maven.google.com/com/google/firebase/firebase-measurement-connector-impl/17.0.5/firebase-measurement-connector-impl-17.0.5-javadoc.jar’が空みたい。。
Chromeで試しにダウンロードしても「失敗 – ファイルがありません」となってしまう。
CDNの不調か何かで配信されてない?なんだろう。

ちょっと別件もあって時間ないので、16.0.7にする理由はないので、16.0.6で様子を見る。


Caused by: java.io.IOException: Response 204: No Content has no content!
	at org.gradle.internal.resource.transport.http.HttpResponseResource.openStream(HttpResponseResource.java:123)
	at org.gradle.internal.resource.transfer.ProgressLoggingExternalResourceAccessor$ProgressLoggingExternalResource.openStream(ProgressLoggingExternalResourceAccessor.java:62)
	at org.gradle.internal.resource.transfer.AccessorBackedExternalResource.withContentIfPresent(AccessorBackedExternalResource.java:135)
	... 140 more

org.gradle.api.resources.ResourceException: Could not get resource 'https://maven.google.com/com/google/firebase/firebase-measurement-connector-impl/17.0.5/firebase-measurement-connector-impl-17.0.5-javadoc.jar'.
	at org.gradle.internal.resource.ResourceExceptions.failure(ResourceExceptions.java:74)
	at org.gradle.internal.resource.ResourceExceptions.getFailed(ResourceExceptions.java:57)
	at org.gradle.internal.resource.transfer.AccessorBackedExternalResource.withContentIfPresent(AccessorBackedExternalResource.java:146)
	at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator$11.call(BuildOperationFiringExternalResourceDecorator.java:237)
	at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator$11.call(BuildOperationFiringExternalResourceDecorator.java:229)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:314)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:304)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:100)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
	at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator.withContentIfPresent(BuildOperationFiringExternalResourceDecorator.java:229)
	at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor.copyToCache(DefaultCacheAwareExternalResourceAccessor.java:199)
	at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor.access$300(DefaultCacheAwareExternalResourceAccessor.java:54)
	at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor$1.create(DefaultCacheAwareExternalResourceAccessor.java:89)
	at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor$1.create(DefaultCacheAwareExternalResourceAccessor.java:81)
	at org.gradle.cache.internal.ProducerGuard$AdaptiveProducerGuard.guardByKey(ProducerGuard.java:97)
	at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor.getResource(DefaultCacheAwareExternalResourceAccessor.java:81)
	at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.downloadByCoords(DefaultExternalResourceArtifactResolver.java:133)
	at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.downloadStaticResource(DefaultExternalResourceArtifactResolver.java:97)
	at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.resolveArtifact(DefaultExternalResourceArtifactResolver.java:66)
	at org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver$RemoteRepositoryAccess.resolveArtifact(ExternalResourceResolver.java:477)
	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.CachingModuleComponentRepository$ResolveAndCacheRepositoryAccess.resolveArtifact(CachingModuleComponentRepository.java:424)
	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.resolveArtifact(ErrorHandlingModuleComponentRepository.java:183)
	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainArtifactResolver.resolveArtifact(RepositoryChainArtifactResolver.java:81)
	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingArtifactResolver.resolveArtifact(ErrorHandlingArtifactResolver.java:46)
	at org.gradle.api.internal.artifacts.query.DefaultArtifactResolutionQuery.addArtifacts(DefaultArtifactResolutionQuery.java:179)
	at org.gradle.api.internal.artifacts.query.DefaultArtifactResolutionQuery.buildComponentResult(DefaultArtifactResolutionQuery.java:168)
	at org.gradle.api.internal.artifacts.query.DefaultArtifactResolutionQuery.createResult(DefaultArtifactResolutionQuery.java:142)
	at org.gradle.api.internal.artifacts.query.DefaultArtifactResolutionQuery.execute(DefaultArtifactResolutionQuery.java:133)
	at com.android.build.gradle.internal.ide.dependencies.ArtifactDependencyGraph.handleSources(ArtifactDependencyGraph.java:351)
	at com.android.build.gradle.internal.ide.dependencies.ArtifactDependencyGraph.createDependencies(ArtifactDependencyGraph.java:309)
	at com.android.build.gradle.internal.ide.ModelBuilder.getDependencies(ModelBuilder.java:815)
	at com.android.build.gradle.internal.ide.ModelBuilder.createAndroidArtifact(ModelBuilder.java:919)
	at com.android.build.gradle.internal.ide.ModelBuilder.createVariant(ModelBuilder.java:583)
	at com.android.build.gradle.internal.ide.ModelBuilder.buildVariant(ModelBuilder.java:538)
	at com.android.build.gradle.internal.ide.ModelBuilder.buildAll(ModelBuilder.java:239)
	at com.android.build.gradle.internal.ide.ModelBuilder.buildAll(ModelBuilder.java:148)
	at org.gradle.tooling.internal.provider.runner.DefaultBuildController.getParameterizedModel(DefaultBuildController.java:99)
	at org.gradle.tooling.internal.provider.runner.DefaultBuildController.getModel(DefaultBuildController.java:81)
	at org.gradle.tooling.internal.consumer.connection.InternalBuildActionAdapter$2.getModel(InternalBuildActionAdapter.java:77)
	at org.gradle.tooling.internal.consumer.connection.BuildControllerAdapter.getModel(BuildControllerAdapter.java:62)
	at org.gradle.tooling.internal.consumer.connection.AbstractBuildController.findModel(AbstractBuildController.java:57)
	at com.android.tools.idea.gradle.project.sync.ng.SelectedVariantChooser.syncAndAddVariant(SelectedVariantChooser.java:148)
	at com.android.tools.idea.gradle.project.sync.ng.SelectedVariantChooser.selectVariantForAppOrLeaf(SelectedVariantChooser.java:129)
	at com.android.tools.idea.gradle.project.sync.ng.SelectedVariantChooser.chooseSelectedVariants(SelectedVariantChooser.java:79)
	at com.android.tools.idea.gradle.project.sync.ng.SyncProjectModels.populate(SyncProjectModels.java:92)
	at com.android.tools.idea.gradle.project.sync.ng.SyncAction.execute(SyncAction.java:59)
	at com.android.tools.idea.gradle.project.sync.ng.SyncAction.execute(SyncAction.java:33)
	at org.gradle.tooling.internal.consumer.connection.InternalBuildActionAdapter.execute(InternalBuildActionAdapter.java:80)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner.buildResult(ClientProvidedBuildActionRunner.java:81)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner.access$100(ClientProvidedBuildActionRunner.java:38)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner$1.buildFinished(ClientProvidedBuildActionRunner.java:62)
	at sun.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.event.DefaultListenerManager$ListenerDetails.dispatch(DefaultListenerManager.java:370)
	at org.gradle.internal.event.DefaultListenerManager$ListenerDetails.dispatch(DefaultListenerManager.java:352)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58)
	at org.gradle.internal.event.DefaultListenerManager$EventBroadcast$ListenerDispatch.dispatch(DefaultListenerManager.java:340)
	at org.gradle.internal.event.DefaultListenerManager$EventBroadcast$ListenerDispatch.dispatch(DefaultListenerManager.java:327)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:42)
	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:230)
	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:149)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58)
	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:324)
	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:234)
	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:140)
	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy15.buildFinished(Unknown Source)
	at org.gradle.initialization.DefaultGradleLauncher.finishBuild(DefaultGradleLauncher.java:165)
	at org.gradle.initialization.DefaultGradleLauncher.finishBuild(DefaultGradleLauncher.java:131)
	at org.gradle.internal.invocation.GradleBuildController$2.call(GradleBuildController.java:87)
	at org.gradle.internal.invocation.GradleBuildController$2.call(GradleBuildController.java:83)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:154)
	at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:38)
	at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:96)
	at org.gradle.internal.invocation.GradleBuildController.configure(GradleBuildController.java:83)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner.run(ClientProvidedBuildActionRunner.java:70)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
	at 

more

tedivm/stash(phpキャッシュライブラリ)でPHP Fatal error: Uncaught Error: Call to protected method

ドキュメント通りにキャッシュディレクトリを指定するとprotected methodだよって怒られます。

https://packagist.org/packages/tedivm/stash


$driver 	= new Stash\Driver\FileSystem();
$driver->setOptions( [ 'path' => dirname(__FILE__) . '/cache/' ] );
$pool = new Stash\Pool( $driver );


PHP Fatal error:  Uncaught Error: Call to protected method Stash\Driver\FileSystem::setOptions() from context ''

コードを見てみると、setOptionsはprotectedに変更されています。


protected function setOptions(array $options = array())

なのでドライバーのインスタンス化の際に指定します。


$driver = new Stash\Driver\FileSystem( [ 'path' => dirname(__FILE__) . '/cache/' ] );
$pool = new Stash\Pool( $driver );