Amplify.Auth.fetchAuthSession() userPoolTokens is null when shrinking the apk - android

I am using the amplify libraries for flutter to connect to my aws backend. After a successful call to Amplify.Auth.signIn() I use Amplify.Auth.fetchAuthSession() to access the current credentials. Like that:
final result = await Amplify.Auth.fetchAuthSession(
options: CognitoSessionOptions(getAWSCredentials: true),
);
if (!result.isSignedIn) return const None();
if (result is CognitoAuthSession) {
return Some(result.userPoolTokens.idToken);
}
But when I build an apk with flutter using the following command my code breaks.
flutter build apk
Because result.userPoolTokens is suddenly null and I get a NoSuchMethodError. The getter 'idToken' was called on null. But if I disable shrinking and build the apk with the following command everything works again.
flutter build apk --no-shrink
So I think it has something to do with the shrinking and I would prefer to shrink my app because the shrinked apk is significantly smaller.
Would appreciate any help.

This is likely due to inadequate rules being applied for the R8 shrinker.
The Amplify Android library did not vend any consumer-rules.pro until version 1.6.10 (see release notes), which was just released January 22nd, 2021.
The latest version of Amplify Flutter is 0.0.2-dev.1, and it consumes version 1.6.8 of the Android library. I've raised an issue on their GitHub repository, to update to 1.6.10.
In the meantime, you could try to apply these rules in your top-level application project.
-keep class com.amazon.** { *; }
-keep class com.amazonaws.** { *; }
-keep class com.amplifyframework.** { *; }

Related

Proguard rules for Jetpack GameActivity

I'm trying to use Jetpack GameActivity in my project, but I encounter a strange issue with Proguard. My project has 2 modules, app and my-lib:
my-lib module has MyActivity which extends GameActivity:
api 'androidx.games:games-activity:1.2.1'
app module has MainActivity which extends MyActivity from my-lib module
implementation project(":my-lib")
When I built my project in Release build and had Proguard enabled, I got a native crash:
Abort message: 'Unable to find method setWindowFlags'
=> I tried inspecting GameActivity class from my APK, setWindowFlags method didn't exist at all, which means Proguard has removed it, that's why the native part of the GameActivity library couldn't find the method and it threw an error.
Then, I tried to fix it, by adding Proguard rule like this:
-keep, includedescriptorclasses class com.google.androidgamesdk.GameActivity { *; }
But unfortunately, I got another native crash:
Abort message: 'Unable to find field left'
=> Why does this happen? I tried inspecting the APK again, but have no idea why
Anyway, how can I deal with this situation? Does Jetpack GameActivty need to add Proguard rules to keep methods that will be used by the native part?
There is a know issue in version 1.2.1 and before: the java functions called by native code only were stripped out by proguard for the release build. Version 1.2.2-alpha01 has fixed that and a few other important potential issues, including the static library release in the AAR. To use the 1.2.2-alpha01+:
Add the latest version to the dependency: 1.2.2-alpha01+
Use C/C++ static lib release in the AAR.
add the following or something similar to your project's existing CMakeLists.txt
find_package(game-activity REQUIRED CONFIG)
add_library(${PROJECT_NAME} SHARED sth.cpp) #<=== this is your own.
target_link_libraries(${PROJECT_NAME} game-activity::game-activity_static
# optional: does not hurt to add it; refer to the official doc for update.
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
If want to use the source code directly(not recommended), do something similar to this:
# Find GameActivity sources to build.
find_package(game-activity REQUIRED CONFIG)
get_target_property(GAME_ACTIVITY_INCLUDE_PATH
game-activity::game-activity
INTERFACE_INCLUDE_DIRECTORIES)
string(REPLACE "include" "" GAME_ACTIVITY_SRCS ${GAME_ACTIVITY_INCLUDE_PATH})
file(GLOB_RECURSE GAME_ACTIVITY_SRCS
${GAME_ACTIVITY_INCLUDE_PATH}/*.c*)
add_library(${PROJECT_NAME} SHARED
sth.cpp. #<== this is your own file
${GAME_ACTIVITY_SRCS})
target_link_libraries(${PROJECT_NAME} PUBLIC
android log
game-activity::game-activity
# other libs
)
Note: it is still just 3 source files now, and you can unzip the latest AAR and list them explicitly like:
add_library(${PROJECT_NAME} SHARED
sth.cpp. #<== this is your own file
${GAME_ACTIVITY_INCLUDE_PATH}/game-activity/GameActivity.cpp
${GAME_ACTIVITY_INCLUDE_PATH}/game-activity/native_app_glue/android_native_app_glue.c
${GAME_ACTIVITY_INCLUDE_PATH}/game-text-input/gametextinput.cpp)
The glob way might be better for future compatibility reasons; but it is not cmake recommended way to do things.
Handle the the "back" button press to exit app either from Kotlin/Java side(handle KEYCODE_BACK in onKeyDown()) or native code (AKEYCODE_BACK in input key event processing).
Referring to the documentation page and probably the list above, you should be able to get your project going. The simple fact is this: all of the C/C++ things are inside AAR, under the prefab sub-directory, you even can copy it out and directly put into your own source tree. This Pull Request might help (but not totally sure).
If you see something or like some new things, please create a bug.
I had the same issues as you and I solved this by adding the following line to my proguard-rules.pro file:
-keep class com.google.androidgamesdk.** { *; }
Of course then I had other proguard related errors so I had to add these
additional lines:
-keep class androidx.core.graphics.Insets { *; }
-keep class androidx.core.view.** { *; }
-keep class org.fmod.** { *; }
Of course you will have different errors in your build, but hopefully this will help you.

Finotes not reporting issues

I am using Automated bug reporting SDK finotes in android.
I had integrated the sdk and it was reporting issues during development
but I created a release build for testing. Looks like it is not reporting issues anymore.
Any help will be appreciated.
As per their documentation make sure that you add the following in your pro-guard configuration
-keep class com.finotes.android.finotescore.* { *; }
-keepclassmembers class * {
#com.finotes.android.finotescore.annotation.Observe *;
}
Also make sure that, in init() function doesn’t have their dry run turned ON
dryRun flag will prevent the issues from syncing to their dashboard.
For release build, change init() in Application class to,
Fn.init(this);

How can I obfuscate my sdk coded with kotlin (and get rid of Metadata)

I'm developing a SDK (Android library), and I have to obfuscate a large part of my code so the customer may not try and play with internal code.
My lib is coded in kotlin, and I used proguard to obfuscate the code. Problem is that there are still #kotlin.Metadata (runtime) annotations inside the code after compile and obfuscation. With those annotations, it's really easy to retrieve the java code that originated this "(not-so-)obfuscated" bytecode.
I first thought it was my fault, and my project had too many entropy sources that might have induced this behaviour, so I made a sample project to prove that the problem does not come from my sdk implementation.
I created a new project with AS, then a lib module with 2 files:
facade.kt is my facade class, the one that I do not wish to obfuscate, so the customer may use it:
package com.example.mylibrary
class MyFacade(val internalClass:InternalClass) {
fun doSomething() {
internalClass.doSomething(
firstArgument=1,
secondArgument=2
)
}
}
and in this sample, internal.kt holds the classes that I want to obfuscate:
package com.example.mylibrary
class InternalClass {
fun doSomething(firstArgument: Int, secondArgument: Int) {
System.out.println("Arguments are : $firstArgument, $secondArgument")
}
}
The proguard rules are injected into gradle project with this release closure:
buildTypes {
release {
minifyEnabled true
proguardFiles 'proguard-rules.pro'
}
}
And here is proguard-rules.pro (only one line, nothing more) :
-keep class com.example.mylibrary.MyFacade {*;}
The result: when I ./gradlew clean myLib:assembleRelease, I do obtain an aar in which my facade is kept, and my internal class has been renamed in 'a', with one method 'a', except that the class is still annotated with kotlin #Metadata, which holds every information that helps the decompiler retrieve the original class name, the method, attribute and argument names, etc...
So my code is not so obfuscated at all...
#Metadata(
mv = {1, 1, 7},
bv = {1, 0, 2},
k = 1,
d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0016\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00062\u0006\u0010\u0007\u001a\u00020\u0006¨\u0006\b"},
d2 = {"Lcom/example/mylibrary/InternalClass;", "", "()V", "doSomething", "", "firstArgument", "", "secondArgument", "mylibrary_release"}
)
public final class a {
...
}
So my question: is it possible to get rid of those annotations, am I the only one facing this problem, or have I missed something?
Finally, I found a way to delete Kotlin metadata annotations.
In order to hide Kotlin metadata annotations, you need to enable R8 full mode.
Here is the information about my environment.
Environment
OS: macOS 10.15.1
Android Studio: 3.5.1
Gradle: 5.4.1
Android Gradle Tool: 3.5.2
What you have to do is just add properties to gradle.properties like below
gradle.properties
android.enableR8.fullMode=true
And here is my Proguard Rules
proguard-rules.pro
-dontwarn kotlin.**
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
FYI, R8 full mode is still testing now, so sometimes it doesn't work well. However, for me, it works perfectly for now.
There is some plugin dedicated for this kind of this request : https://github.com/oliver-jonas/unmeta
This plugin allows removing all Kotlin #Metadata / #DebugMetadata annotations from generated class files. This is safe to do as long as:
you do not intend to use the resulting binaries as a Kotlin library (#Metadata annotations are used to determine Kotlin function definitions),
you are not using Kotlin Reflection (certain reflection functionality depends on the presence of the #Metadata annotations).
Must be careful because when removing the metadata kotlin may your application or your library will not work.

GCM registration works for debug APK but not release APK

The debug build of my APK always successfully registers with GCM. I've just built the first release version of my APK. I can install and run the release version, via Android Studio, on my USB-connected device. However GCM registration always fails for the release version.
private static final String TAG = "GcmRegIntentService";
MyRegistrationEpt backendRegService = getRegistrationService();
try {
synchronized (TAG) {
InstanceID instanceID = InstanceID.getInstance(appContext);
String token = instanceID.getToken(GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.i(TAG, "before register, token: " + token);
backendRegService.register(token).execute();
}
} catch (Exception ex) {
Log.i(TAG, "Error: " + ex.getMessage());
}
private MyRegistrationEpt getRegistrationService() {
MyRegistrationEpt.Builder builder = new MyRegistrationEpt.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl("https://some_valid_app.appspot.com/_ah/api/")
.setApplicationName(getResources().getString(R.string.app_name));
return builder.build();
}
When this code runs this is the log:
08-21 12:52:54.225 4145-13398/technology.grandma.margriver I/GcmRegIntentService﹕ before register, token: <some_long_string>
08-21 12:52:55.430 4145-13398/technology.grandma.margriver I/GcmRegIntentService﹕ Error: 404 Not Found
I have narrowed down the problem to be related to proguard stripping required GCM classes from my build. If I set "minifyEnabled false" in build.gradle the problem disappears. I'm using Google Play services API level 7.8.0. Page https://developers.google.com/android/guides/setup says:
"ProGuard directives are included in the Play services client libraries to preserve the required classes. The Android Plugin for Gradle automatically appends ProGuard configuration files in an AAR (Android ARchive) package and appends that package to your ProGuard configuration. During project creation, Android Studio automatically creates the ProGuard configuration files and build.gradle properties for ProGuard use. To use ProGuard with Android Studio, you must enable the ProGuard setting in your build.gradle buildTypes. For more information, see the ProGuard guide."
I interpret this to mean that I do not need to manually need to add any proguard rules for GCM. Can anyone explain the cause of this error and suggest how I fix it?
I fixed this problem. The problem was not caused by proguard stripping GCM classes but by proguard stripping types and annotations needed to connect to by Google App Engine API client. To fix this I added these lines to my proguard rules:
# Needed by google-api-client to keep generic types and #Key annotations accessed via reflection
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
-keepclassmembers class * {
#com.google.api.client.util.Key <fields>;
}
See https://developers.google.com/api-client-library/java/google-http-java-client/setup#proguard.
SHA1 Certificate might be needed to be added in the API console . For Both debug and release

Removing uses of TestFlight SDK with ProGuard

How can I automatically remove all uses of TestFlight SDK from my app? For example, all passCheckpoint calls:
TestFlight.passCheckpoint("FreemiumDialog opened");
My (ProGuard-obfuscated) release builds should not even attempt to send any info to TestFlight, yet I do not want to manually toggle between having TestFlight jar & its uses in my codebase.
This ProGuard configuration removes all calls to TestFlight SDK:
# Remove all TestFlight SDK calls, e.g. TestFlight.takeOff( ... );
# and TestFlight.passCheckpoint( ... );
-assumenosideeffects class com.testflightapp.lib.TestFlight { *; }
-dontwarn org.msgpack.**
Note: without the last line, ProGuard fails with a bunch of warnings like:
Warning: org.msgpack.template.builder.BeansBuildContext: can't find
referenced class javassist.CtClass
Warning: org.msgpack.util.json.JSONUnpacker: can't find referenced class > org.json.simple.parser.JSONParser
This is because the TestFlightLib jar (at least version 1.3) contains and uses a library called MessagePack. We need to either -keep it or mute the warnings. Above I'm muting warnings, since the whole point here is not to use TestFlight in release builds.

Categories

Resources