Skip to content

Commit

Permalink
Merge pull request #15 from AbolfaZlRezaEe/feature/auto_init
Browse files Browse the repository at this point in the history
Implement auto-init mechanism
  • Loading branch information
AbolfaZlRezaEe authored Aug 10, 2023
2 parents c2bed47 + 032f03a commit 66d24d5
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 12 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,37 @@ dependencies {
}
```

3. After you followed the two steps above, you should sync the project and wait for Gradle to download all dependencies it needs. when syncing is finished, in your `Application` class, you should init the library with the parameters you want. the result will be something like this(for more information you can check the code and see documentation there):
3. After you followed the two steps above, you should sync the project and wait for Gradle to download all dependencies it needs. when syncing is finished, you have two options for initializing the library:

- You can initialize the library within the `Manifest` file. The only thing you need is your `OpenWeatherMap` ApiKey which you recieved from the website. After that in your `Manifest` file, you must add these two metadatas like bellow:

```xml
<application>

<meta-data
android:name="weather_not_found.auto_init_enabled"
android:value="true"/>

<meta-data
android:name="weather_not_found.open_weather_api_key"
android:value="Your Open Weather ApiKey"/>

</application>
```

- Or maybe you want to initialize the library with a lot more configurations. For that, first make sure you disabled auto init mechanism in `Manifest` file like bellow:

```xml
<application>

<meta-data
android:name="weather_not_found.auto_init_enabled"
android:value="false"/>

</application>
```

And then, initialize the library using `init` function like bellow:

```kotlin
class BaseApplication : Application() {
Expand Down Expand Up @@ -103,6 +133,8 @@ In some situations, WeatherNotFound will log several errors which tells you what

- `Validation failed! Your Api key is not working...`: This is a log that you might see in your logcat section of Android Studio. if you are running [Sample Application](https://github.com/AbolfaZlRezaEe/WeatherNotFound/tree/develop/app) and saw this, you should check `README.md` file of Sample Application module and follow the steps correctly. If you are using the library in your own application, please make sure you followed [these instructions](https://github.com/AbolfaZlRezaEe/WeatherNotFound/tree/sample_app_readme#using-weathernotfound-in-your-project) correctly!

- `You are not allowed to call init() function if auto-init mechanism enabled!`: This run-time exception will occur when you don't disable auto-init mechanism and also call `init` function of library in code! Please either disable the auto-init with `meta-data` tag in `Manifest` file, or remove `init` function from the code!

> Don't forget that if you just created your Apikey, it takes some time to enabling it from [OpenWeatherMap](https://openweathermap.org/). So wait some minutes and then try again.
## Contribution
Expand Down
6 changes: 4 additions & 2 deletions WeatherNotFound/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ android {
dependencies {
// Core Dependencies
val appCompatVersion = "1.6.1"

implementation("androidx.appcompat:appcompat:$appCompatVersion")

// Network Dependencies
Expand All @@ -67,14 +66,17 @@ dependencies {
// Kotlin Coroutines Dependencies
val coroutinesVersion = "1.6.4"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")

// Auto-init Dependency
val autoInitVersion = "1.1.1"
implementation("androidx.startup:startup-runtime:$autoInitVersion")
}

publishing {
publications {
register<MavenPublication>("release") {
groupId = "com.personal"
artifactId = "WeatherNotFound"
version = "1.0.0"

afterEvaluate {
from(components["release"])
Expand Down
13 changes: 12 additions & 1 deletion WeatherNotFound/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data android:name="me.learning.weathernotfound.presentation.AutoInitializer"
android:value="androidx.startup" />
</provider>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package me.learning.weathernotfound.presentation

import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.os.Build
import androidx.startup.Initializer

internal class AutoInitializer : Initializer<WeatherNotFound> {
internal companion object {
private const val MANIFEST_METADATA_KEY_AUTO_INIT_ENABLED =
"weather_not_found.auto_init_enabled"

private const val MANIFEST_METADATA_KEY_OPEN_WEATHER_MAP_APIKEY =
"weather_not_found.open_weather_api_key"
}

override fun create(context: Context): WeatherNotFound {
return WeatherNotFound.getInstance().apply {
if (autoInitEnabled(context = context)) {
autoInit(
context = context,
openWeatherApiKey = getOpenWeatherApiKey(context = context)
)
}
}
}

override fun dependencies(): MutableList<Class<out Initializer<*>>> = mutableListOf()

private fun getApplicationInfo(context: Context): ApplicationInfo {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.getApplicationInfo(
context.packageName,
PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
)
} else {
context.packageManager
.getApplicationInfo(
context.packageName,
PackageManager.GET_META_DATA
)
}
}

private fun autoInitEnabled(
context: Context,
defaultValue: Boolean = false
):Boolean{
return getApplicationInfo(context).metaData.getBoolean(
MANIFEST_METADATA_KEY_AUTO_INIT_ENABLED,
defaultValue
)
}

private fun getOpenWeatherApiKey(
context: Context,
defaultValue: String = ""
): String {
return getApplicationInfo(context).metaData.getString(
MANIFEST_METADATA_KEY_OPEN_WEATHER_MAP_APIKEY,
defaultValue
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class WeatherNotFound private constructor() {
private const val HEADER_VALUE_DEFAULT_RESPONSE_UNIT = "metric"

private var INSTANCE: WeatherNotFound? = null
private var initCalled = false
private var manualInitCalled = false
private var autoInitCalled = false

/**
* @return the singleton instance of WeatherNotFound
Expand Down Expand Up @@ -74,9 +75,11 @@ class WeatherNotFound private constructor() {
connectTimeoutInSeconds: Long? = null,
cacheMechanismEnabled: Boolean = false,
) {
checkAutoInitCalledOrNot()

checkInternetPermission(context)

setInitCalledState(true)
setInitCalledState()

OPEN_WEATHER_API_KEY = openWeatherApiKey
// Todo: For now, SDK can just support Json responses! Other formats will be added soon.
Expand Down Expand Up @@ -107,6 +110,20 @@ class WeatherNotFound private constructor() {
validateOpenWeatherApiKey {}
}

/**
* Initialize library by [AutoInitializer] if user enable it in [Manifest] file.
*
* @param context
* @param openWeatherApiKey which provided in the [Manifest] file.
*/
internal fun autoInit(
context: Context,
openWeatherApiKey: String
) {
init(context = context, openWeatherApiKey = openWeatherApiKey)
setAutoInitCalled()
}

/**
* By calling this, every request and operation in WeatherNotFound will be stopped!
*/
Expand Down Expand Up @@ -332,19 +349,37 @@ class WeatherNotFound private constructor() {
}

@Synchronized
private fun setInitCalledState(isCalled: Boolean) {
initCalled = isCalled
private fun setInitCalledState() {
manualInitCalled = true
}

private fun isInitCalled(): Boolean {
return initCalled
return manualInitCalled
}

private fun validateInitFunction() {
if (!isInitCalled()) {
throw IllegalStateException(
"You didn't call init() function of WeatherNotFound! " +
"Make sure you call this function on your Application class!"
"I think you forgot to initialize WeatherNotFound... Please make sure you followed" +
"the initialization instructions correctly!"
)
}
}

@Synchronized
private fun setAutoInitCalled() {
autoInitCalled = true
}

private fun isAutoInitCalled():Boolean{
return autoInitCalled
}

private fun checkAutoInitCalledOrNot() {
if (isAutoInitCalled()) {
throw IllegalStateException(
"You are not allowed to call init() function if auto-init mechanism enabled! " +
"Please make sure you followed the initialization instructions correctly!"
)
}
}
Expand Down
70 changes: 69 additions & 1 deletion app/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,74 @@
## How Sample Project Works?

Before building the project, you should pay attention to one thing! in this directory we have a file called `weatherNotFound.properties`, in this file several parameters defined but no value passed. please read the following definitions about each parameter and then set your own value:
You have two options for using Sample Project:

1. You can use auto-init mechanism which library provided. For that, you should modify the `Manifest` file of the project and enter your ApiKey into the `weather_not_found.open_weather_api_key` metadata. Also, you should change the value of `weather_not_found.auto_init_enabled` metadata to `true`. Don't forget to comment `init` function in `BaseApplication` class. the result should something like bellow:

```xml
<application>

<meta-data
android:name="weather_not_found.auto_init_enabled"
android:value="true"/>

<meta-data
android:name="weather_not_found.open_weather_api_key"
android:value="Your Open Weather ApiKey"/>

</application>
```

```kotlin
class BaseApplication : Application() {

override fun onCreate() {
super.onCreate()

/* WeatherNotFound.getInstance().init(
context = this,
openWeatherApiKey = BuildConfig.OpenWeatherApiKey,
openWeatherResponseLanguage = BuildConfig.OpenWeatherResponseLanguage,
openWeatherResponseUnit = BuildConfig.OpenWeatherResponseUnit,
httpLoggingLevel = HttpLoggingInterceptor.Level.BODY,
cacheMechanismEnabled = true
)*/
}
}
```

After you set these values, Sample project is ready to go!

2. Or, you can use manual initialization by disabling the auto init in `Manifest` file and use `init` function in `BaseApplication` class. The result will be something like bellow:

```xml
<application>

<meta-data
android:name="weather_not_found.auto_init_enabled"
android:value="false"/>

</application>
```

```kotlin
class BaseApplication : Application() {

override fun onCreate() {
super.onCreate()

WeatherNotFound.getInstance().init(
context = this,
openWeatherApiKey = BuildConfig.OpenWeatherApiKey,
openWeatherResponseLanguage = BuildConfig.OpenWeatherResponseLanguage,
openWeatherResponseUnit = BuildConfig.OpenWeatherResponseUnit,
httpLoggingLevel = HttpLoggingInterceptor.Level.BODY,
cacheMechanismEnabled = true
)
}
}
```

But before building the project, you should pay attention to one thing! in this directory we have a file called `weatherNotFound.properties`, in this file several parameters defined but no value passed. please read the following definitions about each parameter and then set your own value:

- `OpenWeatherApiKey`: This is your apikey that you receives from [OpenWeatherMap](https://openweathermap.org/). If you don't have any, click [here](https://home.openweathermap.org/users/sign_up) and follow the steps.

Expand Down
9 changes: 9 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<meta-data
android:name="weather_not_found.auto_init_enabled"
android:value="false"/>

<meta-data
android:name="weather_not_found.open_weather_api_key"
android:value="Your Open Weather ApiKey"/>

</application>

</manifest>

0 comments on commit 66d24d5

Please sign in to comment.