Adds R8 use cases to the repo

down-call-native
Ajesh R 2 months ago
parent 689ef92e41
commit a282b3e72e

@ -3,7 +3,6 @@
# Obsfuscation must be disabled for the build variant that generates Baseline Profile, otherwise # Obsfuscation must be disabled for the build variant that generates Baseline Profile, otherwise
# wrong symbols would be generated. The generated Baseline Profile will be properly applied when generated # wrong symbols would be generated. The generated Baseline Profile will be properly applied when generated
# without obfuscation and your app is being obfuscated. # without obfuscation and your app is being obfuscated.
-dontobfuscate
# Please add these rules to your existing keep rules in order to suppress warnings. # Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin. # This is generated automatically by the Android Gradle plugin.

@ -70,6 +70,7 @@ android {
} }
dependencies { dependencies {
implementation(projects.app.nativelib)
implementation(projects.feature.interests) implementation(projects.feature.interests)
implementation(projects.feature.foryou) implementation(projects.feature.foryou)
implementation(projects.feature.bookmarks) implementation(projects.feature.bookmarks)

@ -0,0 +1 @@
/build

@ -0,0 +1,13 @@
plugins {
id("java-library")
alias(libs.plugins.kotlin.jvm)
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
}
}

@ -0,0 +1,4 @@
package com.example.lib
class MyClass {
}

@ -0,0 +1 @@
/build

@ -0,0 +1,54 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.example.nativelib"
compileSdk = 36
defaultConfig {
minSdk = 21
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
externalNativeBuild {
cmake {
cppFlags("")
}
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
externalNativeBuild {
cmake {
path("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.test.espresso.core)
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,24 @@
package com.example.nativelib
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.nativelib.test", appContext.packageName)
}
}

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

@ -0,0 +1,38 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("nativelib")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
nativelib.cpp
)
# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}
# List libraries link to the target library
android
log)

@ -0,0 +1,10 @@
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_nativelib_NativeLib_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}

@ -0,0 +1,18 @@
package com.example.nativelib
class NativeLib {
/**
* A native method that is implemented by the 'nativelib' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
companion object {
// Used to load the 'nativelib' library on application startup.
init {
System.loadLibrary("nativelib")
}
}
}

@ -0,0 +1,17 @@
package com.example.nativelib
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

@ -16,12 +16,15 @@
package com.google.samples.apps.nowinandroid package com.google.samples.apps.nowinandroid
import android.os.Build.VERSION_CODES
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -50,7 +53,10 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.example.nativelib.NativeLib
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.KVisibility
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -79,6 +85,8 @@ class MainActivity : ComponentActivity() {
val splashScreen = installSplashScreen() val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
accessSecretMessage(LibraryClass())
// We keep this as a mutable state, so that we can track changes inside the composition. // We keep this as a mutable state, so that we can track changes inside the composition.
// This allows us to react to dark/light mode changes. // This allows us to react to dark/light mode changes.
var themeSettings by mutableStateOf( var themeSettings by mutableStateOf(

@ -0,0 +1,42 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid
import android.util.Log
val TAG: String = "R8"
/**
* A class with private members to demonstrate reflection.
*/
class LibraryClass {
private val secretMessage: Message = Message("R8 will remove me")
}
data class Message(
val message: String,
val id: Int = 0
)
// In your app code:
fun accessSecretMessage(instance: LibraryClass) {
// Use Java reflection from Kotlin to access the private field
val secretField = instance::class.java.getDeclaredField("secretMessage")
secretField.isAccessible = true
val message = secretField.get(instance) as Message
Log.d(TAG, message.toString())
}

@ -60,5 +60,6 @@ plugins {
alias(libs.plugins.roborazzi) apply false alias(libs.plugins.roborazzi) apply false
alias(libs.plugins.secrets) apply false alias(libs.plugins.secrets) apply false
alias(libs.plugins.room) apply false alias(libs.plugins.room) apply false
alias(libs.plugins.module.graph) apply true // Plugin applied to allow module graph generation alias(libs.plugins.module.graph) apply true
alias(libs.plugins.kotlin.android) apply false // Plugin applied to allow module graph generation
} }

@ -2,3 +2,11 @@
-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite* { -keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite* {
<fields>; <fields>;
} }
-keepclassmembers,includedescriptorclasses class com.google.samples.apps.nowinandroid.LibraryClass {
private * secretMessage;
}
-printconfiguration r8/full-r8-config.txt # Prints the entire configuration for the app
-printusage r8/usage.txt # Prints where R8 removed code from the app
-printseeds r8/seeds.txt

@ -18,7 +18,7 @@ androidxEspresso = "3.6.1"
androidxHiltNavigationCompose = "1.2.0" androidxHiltNavigationCompose = "1.2.0"
androidxLifecycle = "2.8.7" androidxLifecycle = "2.8.7"
androidxLintGradle = "1.0.0-alpha03" androidxLintGradle = "1.0.0-alpha03"
androidxMacroBenchmark = "1.3.4" androidxMacroBenchmark = "1.4.0-beta02"
androidxMetrics = "1.0.0-beta01" androidxMetrics = "1.0.0-beta01"
androidxNavigation = "2.8.5" androidxNavigation = "2.8.5"
androidxProfileinstaller = "1.4.1" androidxProfileinstaller = "1.4.1"
@ -59,6 +59,9 @@ room = "2.6.1"
secrets = "2.0.1" secrets = "2.0.1"
truth = "1.4.4" truth = "1.4.4"
turbine = "1.2.0" turbine = "1.2.0"
junit = "4.13.2"
junitVersion = "1.2.1"
material = "1.12.0"
[bundles] [bundles]
androidx-compose-ui-test = ["androidx-compose-ui-test", "androidx-compose-ui-testManifest"] androidx-compose-ui-test = ["androidx-compose-ui-test", "androidx-compose-ui-testManifest"]
@ -161,6 +164,9 @@ firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "per
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", version.ref = "room" } room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", version.ref = "room" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
@ -198,3 +204,4 @@ nowinandroid-android-room = { id = "nowinandroid.android.room" }
nowinandroid-android-test = { id = "nowinandroid.android.test" } nowinandroid-android-test = { id = "nowinandroid.android.test" }
nowinandroid-hilt = { id = "nowinandroid.hilt" } nowinandroid-hilt = { id = "nowinandroid.hilt" }
nowinandroid-jvm-library = { id = "nowinandroid.jvm.library" } nowinandroid-jvm-library = { id = "nowinandroid.jvm.library" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

@ -83,3 +83,4 @@ check(JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
https://developer.android.com/build/jdks#jdk-config-in-studio https://developer.android.com/build/jdks#jdk-config-in-studio
""".trimIndent() """.trimIndent()
} }
include(":app:nativelib")

@ -0,0 +1,36 @@
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.samples.apps.nowinandroid/com.google.samples.apps.nowinandroid.MainActivity}: java.util.NoSuchElementException: List is empty.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4048)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4235)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:112)
at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:174)
at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:109)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:81)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2636)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8705)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
Caused by: java.util.NoSuchElementException: List is empty.
at i4.k.m0(SourceFile:22)
at i4.k.l0(SourceFile:12)
at com.google.samples.apps.nowinandroid.MainActivity.onCreate(SourceFile:54)
at android.app.Activity.performCreate(Activity.java:9002)
at android.app.Activity.performCreate(Activity.java:8980)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1526)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4030)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4235) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:112) 
at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:174) 
at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:109) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:81) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2636) 
at android.os.Handler.dispatchMessage(Handler.java:107) 
at android.os.Looper.loopOnce(Looper.java:232) 
at android.os.Looper.loop(Looper.java:317) 
at android.app.ActivityThread.main(ActivityThread.java:8705) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886) 
Loading…
Cancel
Save