Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add firebase analytics #525

Merged
merged 14 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:
run: ./gradlew :updateVersions
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Publish Firebase Analytics
run: ./gradlew :firebase-analytics:publish
- name: Publish Firebase App
run: ./gradlew :firebase-app:publish
- name: Publish Firebase Auth
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ val minSdkVersion by extra(23)
tasks {
register("updateVersions") {
dependsOn(
"firebase-analytics:updateVersion", "firebase-analytics:updateDependencyVersion",
"firebase-app:updateVersion", "firebase-app:updateDependencyVersion",
"firebase-auth:updateVersion", "firebase-auth:updateDependencyVersion",
"firebase-common:updateVersion", "firebase-common:updateDependencyVersion",
Expand Down
173 changes: 173 additions & 0 deletions firebase-analytics/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree

/*
* Copyright (c) 2023 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license.
*/

version = project.property("firebase-analytics.version") as String

plugins {
id("com.android.library")
kotlin("native.cocoapods")
kotlin("multiplatform")
}

android {
val minSdkVersion: Int by project
val compileSdkVersion: Int by project

compileSdk = compileSdkVersion
namespace = "dev.gitlive.firebase.analytics"

defaultConfig {
minSdk = minSdkVersion
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

testOptions {
unitTests.apply {
isIncludeAndroidResources = true
}
}
packaging {
resources.pickFirsts.add("META-INF/kotlinx-serialization-core.kotlin_module")
resources.pickFirsts.add("META-INF/AL2.0")
resources.pickFirsts.add("META-INF/LGPL2.1")
}
lint {
abortOnError = false
}
}

val supportIosTarget = project.property("skipIosTarget") != "true"

kotlin {

targets.configureEach {
compilations.configureEach {
kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes"
}
}

@Suppress("OPT_IN_USAGE")
androidTarget {
instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test)
unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test)
publishAllLibraryVariants()
compilations.configureEach {
kotlinOptions {
jvmTarget = "11"
}
}
}

jvm {
compilations.getByName("main") {
kotlinOptions {
jvmTarget = "17"
}
}
compilations.getByName("test") {
kotlinOptions {
jvmTarget = "17"
}
}
}

if (supportIosTarget) {
iosArm64()
iosX64()
iosSimulatorArm64()
cocoapods {
ios.deploymentTarget = "12.0"
framework {
baseName = "FirebaseAnalytics"
}
noPodspec()
pod("FirebaseAnalytics") {
version = "10.25.0"
extraOpts += listOf("-compiler-option", "-fmodules")
}
}
}

js(IR) {
useCommonJs()
nodejs {
testTask(
Action {
useKarma {
useChromeHeadless()
}
}
)
}
browser {
testTask(
Action {
useKarma {
useChromeHeadless()
}
}
)
}
}

sourceSets {
all {
languageSettings.apply {
val apiVersion: String by project
val languageVersion: String by project
this.apiVersion = apiVersion
this.languageVersion = languageVersion
progressiveMode = true
if (name.lowercase().contains("ios")) {
optIn("kotlinx.cinterop.ExperimentalForeignApi")
}
}
}

getByName("commonMain") {
dependencies {
api(project(":firebase-app"))
implementation(project(":firebase-common"))
}
}

getByName("commonTest") {
dependencies {
implementation(project(":test-utils"))
}
}

getByName("androidMain") {
dependencies {
api("com.google.firebase:firebase-analytics")
}
}
}
}

if (project.property("firebase-analytics.skipIosTests") == "true") {
tasks.forEach {
if (it.name.contains("ios", true) && it.name.contains("test", true)) { it.enabled = false }
}
}

if (project.property("firebase-analytics.skipJsTests") == "true") {
tasks.forEach {
if (it.name.contains("js", true) && it.name.contains("test", true)) { it.enabled = false }
}
}

signing {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(publishing.publications)
}
39 changes: 39 additions & 0 deletions firebase-analytics/firebase_analytics.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Pod::Spec.new do |spec|
spec.name = 'firebase_analytics'
spec.version = '1.8.1'
spec.homepage = ''
spec.source = { :http=> ''}
spec.authors = ''
spec.license = ''
spec.summary = ''
spec.vendored_frameworks = 'build/cocoapods/framework/firebase_analytics.framework'
spec.libraries = 'c++'



spec.pod_target_xcconfig = {
'KOTLIN_PROJECT_PATH' => ':firebase-analytics',
'PRODUCT_MODULE_NAME' => 'firebase_analytics',
}

spec.script_phases = [
{
:name => 'Build firebase_analytics',
:execution_position => :before_compile,
:shell_path => '/bin/sh',
:script => <<-SCRIPT
if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then
echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\""
exit 0
fi
set -ev
REPO_ROOT="$PODS_TARGET_SRCROOT"
"$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \
-Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \
-Pkotlin.native.cocoapods.archs="$ARCHS" \
-Pkotlin.native.cocoapods.configuration="$CONFIGURATION"
SCRIPT
}
]

end
31 changes: 31 additions & 0 deletions firebase-analytics/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@gitlive/firebase-analytics",
"version": "1.12.0",
"description": "Wrapper around firebase for usage in Kotlin Multiplatform projects",
"main": "firebase-analytics.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/GitLiveApp/firebase-kotlin-sdk.git"
},
"keywords": [
"kotlin",
"multiplatform",
"kotlin-js",
"firebase"
],
"author": "dev.gitlive",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/GitLiveApp/firebase-kotlin-sdk/issues"
},
"homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk",
"dependencies": {
"@gitlive/firebase-app": "1.12.0",
"firebase": "9.19.1",
"kotlin": "1.6.10",
"kotlinx-coroutines-core": "1.6.1-native-mt"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application android:usesCleartextTraffic="true" />
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license.
*/

@file:JvmName("tests")
package dev.gitlive.firebase.analytics

import androidx.test.platform.app.InstrumentationRegistry

actual val emulatorHost: String = "10.0.2.2"

actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class IgnoreForAndroidUnitTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package dev.gitlive.firebase.analytics

import android.os.Bundle
import android.os.IBinder
import android.os.Parcelable
import android.util.Size
import android.util.SizeF
import com.google.firebase.analytics.analytics
import com.google.firebase.analytics.setConsent
import dev.gitlive.firebase.Firebase
import kotlinx.coroutines.tasks.await
import java.io.Serializable

actual val Firebase.analytics: FirebaseAnalytics
get() = FirebaseAnalytics(com.google.firebase.Firebase.analytics)

actual class FirebaseAnalytics(val android: com.google.firebase.analytics.FirebaseAnalytics) {
actual fun logEvent(name: String, parameters: Map<String, Any>?) {
android.logEvent(name, parameters?.toBundle())
}
actual fun setUserProperty(name: String, value: String) {
android.setUserProperty(name, value)
}
actual fun setUserId(id: String) {
android.setUserId(id)
}
actual fun resetAnalyticsData() {
android.resetAnalyticsData()
}
actual fun setDefaultEventParameters(parameters: Map<String, String>) {
android.setDefaultEventParameters(parameters.toBundle())
}

actual fun setAnalyticsCollectionEnabled(enabled: Boolean) {
android.setAnalyticsCollectionEnabled(enabled)
}

actual fun setSessionTimeoutInterval(sessionTimeoutInterval: Long) {
android.setSessionTimeoutDuration(sessionTimeoutInterval)
}

actual suspend fun getSessionId(): Long? = android.sessionId.await()

actual fun setConsent(consentSettings: Map<ConsentType, ConsentStatus>) {
consentSettings.entries.associate {
it.key to when (it.value) {
ConsentStatus.GRANTED -> com.google.firebase.analytics.FirebaseAnalytics.ConsentStatus.GRANTED
ConsentStatus.DENIED -> com.google.firebase.analytics.FirebaseAnalytics.ConsentStatus.DENIED
}
}.let { androidConsentSettings ->
android.setConsent {
androidConsentSettings.entries.forEach {
when (it.key) {
ConsentType.AD_PERSONALIZATION ->
this.adPersonalization = it.value

ConsentType.AD_STORAGE ->
this.adStorage = it.value

ConsentType.AD_USER_DATA ->
this.adUserData = it.value

ConsentType.ANALYTICS_STORAGE ->
this.analyticsStorage = it.value
}
}

}
}
}

actual enum class ConsentType {
AD_PERSONALIZATION,
AD_STORAGE,
AD_USER_DATA,
ANALYTICS_STORAGE
}

actual enum class ConsentStatus {
GRANTED,
DENIED
}
}

actual class FirebaseAnalyticsException(message: String): Exception(message)

fun Map<String, Any>.toBundle() = Bundle().apply {
forEach { (key, value) ->
when(value::class) {
String::class -> putString(key, value as String)
Int::class -> putInt(key, value as Int)
Long::class -> putLong(key, value as Long)
Double::class -> putDouble(key, value as Double)
Boolean::class -> putBoolean(key, value as Boolean)
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.gitlive.firebase.analytics

import org.junit.Ignore

actual val emulatorHost: String = "10.0.2.2"

actual val context: Any = ""

actual typealias IgnoreForAndroidUnitTest = Ignore
Loading