diff --git a/.gitignore b/.gitignore index e1969d6..35df9e4 100644 --- a/.gitignore +++ b/.gitignore @@ -81,4 +81,7 @@ lint/tmp/ # lint/reports/ # Detekt Reports -reports/ \ No newline at end of file +reports/ + +# Firebase config +app/google-services.json \ No newline at end of file diff --git a/README.md b/README.md index 3ff2661..0b3225e 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ This is the official repository for the [dev.to](https://dev.to/)'s Android app. ## Design ethos -DEV Android is an [WebView](https://developer.android.com/guide/webapps/webview) based application. This application is inspired by [Basecamp's approach](https://m.signalvnoise.com/basecamp-3-for-ios-hybrid-architecture-afc071589c25). We will grow to include more native code over time. +DEV Android is an [WebView](https://developer.android.com/guide/webapps/webview) based application. This application is inspired by [Basecamp's approach](https://m.signalvnoise.com/basecamp-3-for-ios-hybrid-architecture-afc071589c25). We will grow to include more native code over time. -By leveraging webviews as much as possible, we can smoothly sync up with our web dev work. And where it makes sense, we can re-implement certain things fully native, or build entirely native features. Life's a journey, not a destination. +By leveraging webviews as much as possible, we can smoothly sync up with our web dev work. And where it makes sense, we can re-implement certain things fully native, or build entirely native features. Life's a journey, not a destination. ## Contributions @@ -43,6 +43,11 @@ To see more detail about a task, run gradlew help --task ``` +### Push Notifications + +For Push Notification delivery we use [Pusher Beams](https://pusher.com/beams). In order to get the app running locally you'll need a `google-services.json` configuration file from Firebase, otherwise you'll encounter the following error: `File google-services.json is missing. The Google Services Plugin cannot function without it.` + +You can [sign up or sign in on Firebase](https://firebase.google.com/) account for free in order to get the app working locally. Steps 1-4 under **Firebase for Android Push Notifications** in our [official docs](https://docs.dev.to/backend/pusher/#mobile-push-notifications) show how to set this up in more detail. Drop the resulting `google-services.json` file in the `app` folder and you'll be good to go. ### How to contribute diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7f4141e..6114758 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,7 +30,12 @@ dependencies { implementation(Libs.kotlin_stdlib_jdk8) implementation(Libs.browser) + implementation("com.google.firebase:firebase-messaging:18.0.0") + implementation("com.pusher:push-notifications-android:1.6.2") + testImplementation(Libs.junit) androidTestImplementation(Libs.androidx_test_runner) androidTestImplementation(Libs.espresso_core) } + +apply(plugin = "com.google.gms.google-services") \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a9b493d..f58529d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,8 +13,9 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" - android:usesCleartextTraffic="true" - tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"> + tools:ignore="GoogleAppIndexingWarning,UnusedAttribute" + tools:replace="android:fullBackupContent" + > diff --git a/app/src/main/java/to/dev/dev_android/view/main/view/CustomWebViewClient.kt b/app/src/main/java/to/dev/dev_android/view/main/view/CustomWebViewClient.kt index 6d03a15..7981b35 100644 --- a/app/src/main/java/to/dev/dev_android/view/main/view/CustomWebViewClient.kt +++ b/app/src/main/java/to/dev/dev_android/view/main/view/CustomWebViewClient.kt @@ -9,6 +9,8 @@ import android.webkit.CookieManager import android.webkit.WebView import android.webkit.WebViewClient import androidx.browser.customtabs.CustomTabsIntent +import com.pusher.pushnotifications.PushNotifications +import java.lang.Exception class CustomWebViewClient( private val context: Context, @@ -23,12 +25,32 @@ class CustomWebViewClient( "github.com/sessions/" ) + private var registeredUserNotifications = false + override fun onPageFinished(view: WebView, url: String?) { onPageFinish() view.visibility = View.VISIBLE super.onPageFinished(view, url) } + override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) { + val javascript = "JSON.parse(document.getElementsByTagName('body')[0].getAttribute('data-user')).id" + view?.evaluateJavascript(javascript) { result -> + if (result != "null" && !registeredUserNotifications) { + try { + val userId = result.toString().toInt() + PushNotifications.addDeviceInterest("user-notifications-$userId") + registeredUserNotifications = true + } + catch (e: Exception) { + println(e) + } + } + } + + super.doUpdateVisitedHistory(view, url, isReload) + } + override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { if (view.originalUrl == "https://dev.to/signout_confirm" && url == "https://dev.to/") { view.clearCache(true) diff --git a/app/src/main/java/to/dev/dev_android/view/main/view/MainActivity.kt b/app/src/main/java/to/dev/dev_android/view/main/view/MainActivity.kt index 2da57f5..0ac65da 100644 --- a/app/src/main/java/to/dev/dev_android/view/main/view/MainActivity.kt +++ b/app/src/main/java/to/dev/dev_android/view/main/view/MainActivity.kt @@ -10,6 +10,7 @@ import android.view.View import android.webkit.ValueCallback import android.webkit.WebView import to.dev.dev_android.R +import com.pusher.pushnotifications.PushNotifications import to.dev.dev_android.base.BuildConfig import to.dev.dev_android.base.activity.BaseActivity import to.dev.dev_android.databinding.ActivityMainBinding @@ -29,6 +30,15 @@ class MainActivity : BaseActivity(), CustomWebChromeClient. setWebViewSettings() savedInstanceState?.let { restoreState(it) } ?: navigateToHome() handleIntent(intent) + PushNotifications.start(getApplicationContext(), BuildConfig.pusherInstanceId); + PushNotifications.addDeviceInterest("broadcast"); + } + + override fun onResume() { + if (intent.extras != null && intent.extras["url"] != null) { + binding.webView.loadUrl(intent.extras["url"].toString()) + } + super.onResume() } override fun onSaveInstanceState(outState: Bundle) { diff --git a/build.gradle.kts b/build.gradle.kts index 7dda24b..1855aac 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { val agpVersion = findProperty("version.com.android.tools.build..gradle") as String classpath("com.android.tools.build:gradle:$agpVersion") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") - + classpath("com.google.gms:google-services:4.2.0") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/buildSrc/src/main/kotlin/Android.kt b/buildSrc/src/main/kotlin/Android.kt index 102f5b4..cea3191 100644 --- a/buildSrc/src/main/kotlin/Android.kt +++ b/buildSrc/src/main/kotlin/Android.kt @@ -40,6 +40,8 @@ fun Project.configureBuildConfig(android: BaseExtension) { android.buildTypes.all { resValue("string", "baseUrl", extra.string("chrome.baseUrl")) buildConfigString("baseUrl", extra.string("chrome.baseUrl")) + resValue("string", "pusherInstanceId", extra.string("pusher.instanceId")) + buildConfigString("pusherInstanceId", extra.string("pusher.instanceId")) resValue("string", "userAgent", extra.string("chrome.userAgent")) buildConfigString("userAgent", extra.string("chrome.userAgent")) } diff --git a/gradle.properties b/gradle.properties index dbe48e0..2194105 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,7 @@ ## dev.to configurations chrome.baseUrl=https://dev.to/ chrome.userAgent=DEV-Native-android +pusher.instanceId=cdaf9857-fad0-4bfb-b360-64c1b2693ef3 # Android release configurations android.targetSdkVersion=28