Android

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

Posted by dowell on

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)が必要らしいけどダウンロードボタンどこ?。。
あとでにします。

Linux

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

Posted by dowell on

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
iPhone

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

Posted by dowell on

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


Banner error Request Error: No ad to show.

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

iPhone

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

Posted by dowell on

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でした。

iPhone

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

Posted by dowell on

背景を変えようと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

Other

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

Posted by dowell on

リリースしたアプリが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"

Android

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

Posted by dowell on

事前にロードするリワードだと仕方がないかもしれないけど
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すればもちろん問題ないけど、どうなんだろう。。

Android

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

Posted by dowell on

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
PHP

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

Posted by dowell on

ドキュメント通りにキャッシュディレクトリを指定すると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 );