Let’s say there is a library out there that has a very useful internal
method inside of it.
package org.secret
internal class SecretSauce {
fun onlyForFriends(): Int = 0
}
If you try to use it
import org.secret.SecretSauce
fun myUser(): Boolean {
SecretSauce().onlyForFriends()
return true
}
Kotlin compilation will fail with
> Task :lib:compileKotlin FAILED
e: file:///.../Library.kt:5:19 Cannot access 'class SecretSauce : Any': it is internal in file.
e: file:///.../Library.kt:8:5 Cannot access 'class SecretSauce : Any': it is internal in file.
e: file:///.../Library.kt:8:19 Cannot access 'class SecretSauce : Any': it is internal in file.
That’s good! Library internal bits should not be accessible to you.
However, if we really want we can bypass these errors with
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
Jesse Wilson has a great write-up about this suppression.
Sadly, this workaround is getting phased out starting with
Kotlin 2.1
, and now you will get a warning that will eventually be an insuppressible error.
Is there a different way?
One might wonder, how do src/main
and src/test
compilations work, as they are two different Kotlin invocations in
Gradle and src/test
is able to access src/main
internal
types. If you look at the compiler argument options
you’ll find -Xfriend-paths=path/to/classes/
which is the mechanism for this. If we were naughty, we could use this
same argument for ourselves with an external library.
// Create a configuration we can use to track friend libraries
val friends = configurations.create("friends") {
isCanBeResolved = true
isCanBeConsumed = false
isTransitive = false
}
// Make sure friends libraries are on the classpath
configurations.findByName("implementation")?.extendsFrom(friends)
// Make these libraries friends :)
tasks.withType<KotlinCompile>().configureEach {
friendPaths.from(friends.incoming.artifactView { }.files)
}
// Add libraries you want to
dependencies {
friends("org.example:secret-sauce:1.0.0")
}
Now, we no longer need the suppression, all the internal
types will be accessible as if they were part of our own
library. Sadly, it does seem that Intellij / Android Studio understand these sneaky friendships.
Note, any use of internal
types is completely at your own risk, they are hidden on purpose, and thus you might break
the library or the library owners will break you on the library update.