├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── kotlinc.xml
├── misc.xml
└── vcs.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── seewo
│ │ └── blink
│ │ └── example
│ │ ├── App.kt
│ │ ├── MainActivity.kt
│ │ ├── RouteMetadata.kt
│ │ ├── Uris.kt
│ │ ├── activity
│ │ ├── HomeActivity.kt
│ │ ├── NextActivity.kt
│ │ ├── ReturnResultActivity.kt
│ │ └── interceptor
│ │ │ ├── ExampleInterceptor.kt
│ │ │ ├── LoggerInterceptor.kt
│ │ │ └── RedirectInterceptor.kt
│ │ ├── bean
│ │ └── Navigator.java
│ │ ├── fragment
│ │ ├── FinalFragment.kt
│ │ ├── FragmentContainerActivity.kt
│ │ ├── HomeFragment.kt
│ │ ├── NextFragment.kt
│ │ ├── ReturnResultFragment.kt
│ │ ├── SingleTopFragment.kt
│ │ ├── TempFragment.kt
│ │ └── interceptor
│ │ │ ├── ExampleInterceptor.kt
│ │ │ ├── LoggerInterceptor.kt
│ │ │ └── RedirectInterceptor.kt
│ │ └── ktx
│ │ └── ToastKTX.kt
│ └── res
│ ├── anim
│ ├── fragment_left_in.xml
│ ├── fragment_left_out.xml
│ ├── fragment_right_in.xml
│ ├── fragment_right_out.xml
│ └── fragment_stay.xml
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_fragment.xml
│ ├── activity_home.xml
│ ├── activity_main.xml
│ ├── activity_next.xml
│ ├── activity_return_result.xml
│ ├── fragment_final.xml
│ ├── fragment_home.xml
│ ├── fragment_next.xml
│ ├── fragment_return_result.xml
│ └── fragment_temp.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-anydpi-v33
│ └── ic_launcher.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ ├── ic_launcher_round.webp
│ └── logo.jpeg
│ ├── values-night
│ └── themes.xml
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── blink-activity
├── .gitignore
├── README.md
├── build.gradle
├── consumer-rules.pro
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── seewo
│ │ └── blink
│ │ ├── Blink.kt
│ │ ├── BlinkInitializer.kt
│ │ ├── BlinkKTX.kt
│ │ ├── BlinkParams.kt
│ │ ├── RouteMap.kt
│ │ ├── callback
│ │ └── UriBuilder.java
│ │ ├── interceptor
│ │ ├── AsyncInterceptor.kt
│ │ ├── BaseInterceptor.kt
│ │ ├── Interceptor.kt
│ │ ├── Interceptors.kt
│ │ └── InterruptedException.kt
│ │ └── stub
│ │ ├── ResultHolder.kt
│ │ ├── StubActivity.kt
│ │ ├── StubData.kt
│ │ ├── StubFragment.kt
│ │ └── UtilKTX.kt
│ └── res
│ └── values
│ └── strings.xml
├── blink-annotation
├── .gitignore
├── README.md
├── build.gradle
├── gradle.properties
└── src
│ └── main
│ └── java
│ └── com
│ └── seewo
│ └── blink
│ └── annotation
│ ├── BlinkMetadata.java
│ ├── BlinkUri.java
│ └── metadata
│ └── BaseMetadata.kt
├── blink-fragment
├── .gitignore
├── README.md
├── build.gradle
├── consumer-rules.pro
├── gradle.properties
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── seewo
│ │ └── blink
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── seewo
│ │ │ └── blink
│ │ │ └── fragment
│ │ │ ├── Blink.kt
│ │ │ ├── BlinkFragmentKTX.kt
│ │ │ ├── BlinkInitializer.kt
│ │ │ ├── BlinkKTX.kt
│ │ │ ├── RouteMap.kt
│ │ │ ├── annotation
│ │ │ ├── Background.java
│ │ │ ├── CustomAnimations.kt
│ │ │ ├── KeepAlive.java
│ │ │ ├── Orientation.java
│ │ │ ├── SystemUI.kt
│ │ │ └── bean
│ │ │ │ ├── CustomAnimationSettings.kt
│ │ │ │ └── SystemUiSettings.kt
│ │ │ ├── container
│ │ │ ├── BlinkContainerActivity.kt
│ │ │ ├── BlinkContainerFragment.kt
│ │ │ ├── FragmentTag.kt
│ │ │ └── NullFragment.kt
│ │ │ ├── exception
│ │ │ └── FragmentNotFoundException.kt
│ │ │ ├── interceptor
│ │ │ ├── AsyncInterceptor.kt
│ │ │ ├── BaseInterceptor.kt
│ │ │ ├── Interceptor.kt
│ │ │ ├── Interceptors.kt
│ │ │ └── InterruptedException.kt
│ │ │ ├── mode
│ │ │ ├── LaunchMode.kt
│ │ │ ├── ReEnterFragment.kt
│ │ │ ├── SingleTaskFragment.kt
│ │ │ └── SingleTopFragment.kt
│ │ │ ├── utils
│ │ │ └── SystemUiUtils.kt
│ │ │ └── view
│ │ │ └── WindowInsetsFrameLayout.java
│ └── res
│ │ ├── anim
│ │ ├── empty_animation.xml
│ │ ├── enter_from_bottom.xml
│ │ ├── enter_from_left.xml
│ │ ├── enter_from_right.xml
│ │ ├── enter_from_top.xml
│ │ ├── exit_to_bottom.xml
│ │ ├── exit_to_left.xml
│ │ ├── exit_to_right.xml
│ │ ├── exit_to_top.xml
│ │ ├── fade_in.xml
│ │ └── fade_out.xml
│ │ ├── layout
│ │ ├── blink_container_fragment.xml
│ │ └── blink_fragment_activity.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── seewo
│ └── blink
│ └── ExampleUnitTest.kt
├── blink-ksp
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── seewo
│ │ └── blink
│ │ └── fragment
│ │ └── ksp
│ │ ├── BlinkMetadataEntry.kt
│ │ ├── BlinkProcessorProvider.kt
│ │ ├── BlinkUriEntry.kt
│ │ └── BlinkUriProcessor.kt
│ └── resources
│ └── META-INF
│ └── services
│ └── com.google.devtools.ksp.processing.SymbolProcessorProvider
├── blink-utils
├── .gitignore
├── README.md
├── build.gradle
├── consumer-rules.pro
├── gradle.properties
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── seewo
│ │ └── blink
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── seewo
│ │ │ └── blink
│ │ │ └── utils
│ │ │ └── BlinkKTX.kt
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── seewo
│ └── blink
│ └── ExampleUnitTest.kt
├── build.gradle
├── doc
└── logo.jpeg
├── gradle.properties
├── gradle
├── deploy-local.sh
├── deploy.sh
├── jfrog-push-java.gradle
├── jfrog-push.gradle
├── jitpack-push-java.gradle
├── jitpack-push.gradle
├── local-maven-push.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## 0.1.4
4 |
5 | - fix: 修复StubActivity状态栏不透明的问题
6 |
7 | ## 0.1.3
8 |
9 | - feature: 重构拦截器机制,支持异步导航和异步拦截,并对之前的同步接口保持一定兼容并标记废弃
10 |
11 | ## 0.0.27.14
12 |
13 | - feature: 首个稳定版本
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Blink
2 |
3 | [](https://jitpack.io/#robin8yeung/Blink)
4 | [](./LICENSE)
5 |
6 | Blink的名字取自dota中的"闪烁Blink"技能,敌法师、痛苦女王等英雄通过闪烁技能可以闪现到指定位置。
7 |
8 | 
9 |
10 | ## 框架说明
11 |
12 | Blink是一套基于Uri的Activity路由框架,主要用于App内部的跨组件路由。为了方便老项目快速接入,提供了一些Java友好的接口
13 |
14 | > 详见:[blink-activity](./blink-activity/README.md)
15 |
16 | Blink还包含一套基于Uri的Fragment路由框架,主要用于实现【单Activity应用】。建议基于kotlin接入
17 |
18 | > 详见:[blink-fragment](./blink-fragment/README.md)
19 |
20 | 以上提及的两套框架可以单独使用,也可以同时使用
21 |
22 | **但需知这两套框架属于不同框架,却有许多概念是同名的,所以在同时使用时请注意区分包名**
23 |
24 | ## 版本说明
25 |
26 | > 详见:[CHANGELOG](./CHANGELOG.md)
27 |
28 | ## 特别说明
29 |
30 | Blink提供了纯手动创建路由表的接口,但更推荐通过注解和KSP自动创建路由表
31 |
32 | > 详见:[blink-annotation](./blink-annotation/README.md)
33 |
34 | Blink基于Uri来实现路由,为了更方便开发者操作Uri,Blink提供了一些好用的扩展方法
35 |
36 | > 详见: [blink-utils](./blink-utils/README.md)
37 |
38 | ## 接入指南
39 |
40 | - 设置jitpack仓库地址
41 |
42 | ```groovy
43 | // 工程的build.gradle或settings.gradle配置jitpack maven仓库地址
44 | allprojects {
45 | repositories {
46 | // ...
47 | maven { url 'https://jitpack.io' }
48 | }
49 | }
50 | ```
51 | ```groovy
52 | // 工程的build.gradle配置ksp插件和版本
53 | plugins {
54 | // 配置使用ksp插件,插件版本参考项目使用的kotlin版本和相关文档
55 | id 'com.google.devtools.ksp' version 'your ksp version' apply false
56 | }
57 | ```
58 |
59 | - 添加依赖
60 |
61 | [](https://jitpack.io/#robin8yeung/Blink)
62 |
63 | ```groovy
64 | // 应用build.gradle引入ksp和blink依赖
65 | plugins {
66 | // 引用ksp
67 | id 'com.google.devtools.ksp'
68 | }
69 |
70 | implementation "com.github.robin8yeung.Blink:$module:$version"
71 | ksp "com.github.robin8yeung.Blink:blink-ksp:$version"
72 | ```
73 |
74 | ## License
75 |
76 | Blink is [Apache v2.0 licensed](./LICENSE).
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'com.google.devtools.ksp'
5 | }
6 |
7 | android {
8 | buildFeatures {
9 | viewBinding = true
10 | }
11 |
12 | namespace 'com.seewo.blink.example'
13 | compileSdk 33
14 |
15 | defaultConfig {
16 | applicationId "com.seewo.blink.example"
17 | minSdk 21
18 | targetSdk 28
19 | versionCode 1
20 | versionName "1.0"
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | compileOptions {
30 | sourceCompatibility JavaVersion.VERSION_1_8
31 | targetCompatibility JavaVersion.VERSION_1_8
32 | }
33 | kotlinOptions {
34 | jvmTarget = '1.8'
35 | }
36 | }
37 |
38 | dependencies {
39 |
40 | implementation 'androidx.core:core-ktx:1.7.0'
41 | implementation 'androidx.fragment:fragment-ktx:1.5.7'
42 | implementation 'androidx.appcompat:appcompat:1.6.1'
43 | implementation 'com.google.android.material:material:1.8.0'
44 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
45 | implementation project(':blink-activity')
46 | implementation project(':blink-fragment')
47 | implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.10"
48 | ksp project(':blink-ksp')
49 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
18 |
21 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
39 |
40 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/App.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example
2 |
3 | import android.app.Application
4 | import com.seewo.blink.attach
5 | import com.seewo.blink.example.activity.interceptor.LoggerInterceptor
6 |
7 | class App : Application() {
8 | override fun onCreate() {
9 | super.onCreate()
10 | // 注册路由表
11 | RouteMetadata().inject()
12 | LoggerInterceptor().attach()
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.blink.blinking
6 | import com.seewo.blink.example.databinding.ActivityMainBinding
7 | import com.seewo.blink.example.fragment.FragmentContainerActivity
8 |
9 | class MainActivity : AppCompatActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | val binding = ActivityMainBinding.inflate(layoutInflater)
13 | setContentView(binding.root)
14 | binding.button.setOnClickListener {
15 | blinking("blink://example/activity")
16 | }
17 | binding.buttonFragment.setOnClickListener {
18 | FragmentContainerActivity.start(it.context)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/RouteMetadata.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example
2 |
3 | import com.seewo.blink.annotation.BlinkMetadata
4 | import com.seewo.blink.annotation.metadata.BaseMetadata
5 |
6 | @BlinkMetadata
7 | class RouteMetadata : BaseMetadata()
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/Uris.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example
2 |
3 | object Uris {
4 | private const val BASE_URI = "blink://example"
5 |
6 | // Activity
7 | const val ACTIVITY = "$BASE_URI/activity"
8 | const val HOME_ACTIVITY = "$BASE_URI/home/activity"
9 | const val NEXT = "$BASE_URI/next"
10 | const val RETURN_RESULT = "$BASE_URI/return/result"
11 | const val NOT_EXISTS = "$BASE_URI/not_exists"
12 |
13 | // Fragment
14 | const val FRAGMENT = "$BASE_URI/fragment"
15 | const val NEXT_FRAGMENT = "$BASE_URI/next/fragment"
16 | const val RETURN_RESULT_FRAGMENT = "$BASE_URI/return/result/fragment"
17 | const val TEMP_FRAGMENT = "$BASE_URI/temp"
18 | const val FINAL_FRAGMENT = "$BASE_URI/final"
19 | const val SINGLE_TOP_FRAGMENT = "$BASE_URI/singleTop"
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/activity/HomeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.activity
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.os.Bundle
6 | import android.util.Log
7 | import androidx.appcompat.app.AppCompatActivity
8 | import com.seewo.blink.annotation.BlinkUri
9 | import com.seewo.blink.attach
10 | import com.seewo.blink.blink
11 | import com.seewo.blink.blinking
12 | import com.seewo.blink.detach
13 | import com.seewo.blink.example.Uris
14 | import com.seewo.blink.example.activity.interceptor.ExampleInterceptor
15 | import com.seewo.blink.example.bean.Navigator
16 | import com.seewo.blink.example.databinding.ActivityHomeBinding
17 | import com.seewo.blink.example.ktx.toast
18 | import com.seewo.blink.utils.append
19 | import com.seewo.blink.utils.buildUri
20 |
21 | @BlinkUri(value = [Uris.HOME_ACTIVITY, Uris.ACTIVITY])
22 | class HomeActivity : AppCompatActivity() {
23 | private val interceptor = ExampleInterceptor().apply {
24 | attach()
25 | }
26 |
27 | @SuppressLint("SetTextI18n")
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | val binding = ActivityHomeBinding.inflate(layoutInflater)
31 | setContentView(binding.root)
32 | binding.next.setOnClickListener {
33 | blink(Uris.NEXT).onFailure {
34 | Log.e("BLINK", it.message, it)
35 | toast(it.message)
36 | }
37 | // blinking(Uris.NEXT, onIntercepted = {
38 | // it ?: return@blinking
39 | // Log.e("BLINK", it.message, it)
40 | // toast(it.message)
41 | // })
42 | }
43 | binding.deny.setOnCheckedChangeListener { _, checked ->
44 | if (checked) {
45 | interceptor.attach()
46 | } else {
47 | interceptor.detach()
48 | }
49 | }
50 |
51 | binding.nextWithParam.setOnClickListener {
52 | blinking(Uris.RETURN_RESULT.buildUri {
53 | append("navigator", Navigator.BLINK)
54 | }) {
55 | if (it.resultCode == Activity.RESULT_OK) {
56 | toast("返回结果: ${it.data?.getStringExtra("result")}")
57 | } else {
58 | toast("返回结果: 无")
59 | }
60 | }
61 | }
62 | }
63 |
64 | override fun onDestroy() {
65 | super.onDestroy()
66 | interceptor.detach()
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/activity/NextActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.activity
2 |
3 | import android.content.pm.PackageManager
4 | import android.os.Bundle
5 | import android.util.Log
6 | import androidx.appcompat.app.AppCompatActivity
7 | import com.seewo.blink.annotation.BlinkUri
8 | import com.seewo.blink.attach
9 | import com.seewo.blink.blinking
10 | import com.seewo.blink.createBlinkIntent
11 | import com.seewo.blink.detach
12 | import com.seewo.blink.example.Uris
13 | import com.seewo.blink.example.activity.interceptor.RedirectInterceptor
14 | import com.seewo.blink.example.databinding.ActivityNextBinding
15 | import com.seewo.blink.example.ktx.toast
16 |
17 | @BlinkUri(Uris.NEXT)
18 | class NextActivity : AppCompatActivity() {
19 | private val redirectInterceptor = RedirectInterceptor()
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | val binding = ActivityNextBinding.inflate(layoutInflater)
23 | setContentView(binding.root)
24 | binding.next.setOnClickListener {
25 | blinking(Uris.NOT_EXISTS, onIntercepted = {
26 | it ?: return@blinking
27 | Log.e("BLINK", it.message, it)
28 | toast(it.message)
29 | })
30 | Log.e("BLINK", "resolve ${packageManager.resolveActivity(Uris.NOT_EXISTS.createBlinkIntent(), PackageManager.MATCH_DEFAULT_ONLY)}")
31 | }
32 | binding.home.setOnCheckedChangeListener { _, checked ->
33 | if (checked) {
34 | redirectInterceptor.attach()
35 | } else {
36 | redirectInterceptor.detach()
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/activity/ReturnResultActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.activity
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.appcompat.app.AppCompatActivity
7 | import com.seewo.blink.annotation.BlinkUri
8 | import com.seewo.blink.enumParams
9 | import com.seewo.blink.example.Uris
10 | import com.seewo.blink.example.bean.Navigator
11 | import com.seewo.blink.example.databinding.ActivityReturnResultBinding
12 |
13 | @BlinkUri(Uris.RETURN_RESULT)
14 | class ReturnResultActivity : AppCompatActivity() {
15 | private val navigator by enumParams("navigator")
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | val binding = ActivityReturnResultBinding.inflate(layoutInflater)
20 | setContentView(binding.root)
21 | binding.params.text = "欢迎使用: $navigator"
22 | binding.result.setOnClickListener {
23 | setResult(Activity.RESULT_OK, Intent().putExtra("result", "再见"))
24 | finish()
25 | }
26 | binding.finish.setOnClickListener {
27 | finish()
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/activity/interceptor/ExampleInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.activity.interceptor
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import androidx.core.net.toUri
6 | import com.seewo.blink.example.Uris
7 | import com.seewo.blink.interceptor.AsyncInterceptor
8 | import com.seewo.blink.interrupt
9 |
10 | class ExampleInterceptor: AsyncInterceptor {
11 | override fun filter(intent: Intent) = intent.data?.path == Uris.NEXT.toUri().path
12 |
13 | override suspend fun process(context: Context, intent: Intent) {
14 | interrupt("拦截器: 禁止跳转")
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/activity/interceptor/LoggerInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.activity.interceptor
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.util.Log
6 | import com.seewo.blink.interceptor.AsyncInterceptor
7 |
8 | class LoggerInterceptor: AsyncInterceptor {
9 | override fun priority() = 1
10 |
11 | override suspend fun process(context: Context, intent: Intent) {
12 | Log.i("LoggerInterceptor", "from $context to $intent data: ${intent.dataString}")
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/activity/interceptor/RedirectInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.activity.interceptor
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import androidx.core.net.toUri
6 | import com.seewo.blink.example.Uris
7 | import com.seewo.blink.interceptor.AsyncInterceptor
8 |
9 | class RedirectInterceptor: AsyncInterceptor {
10 | override fun filter(intent: Intent): Boolean = intent.data?.path == Uris.NOT_EXISTS.toUri().path!!
11 |
12 | override fun priority() = 2
13 |
14 | override suspend fun process(context: Context, intent: Intent) {
15 | intent.apply {
16 | data = Uris.HOME_ACTIVITY.toUri()
17 | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/bean/Navigator.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.bean;
2 |
3 | public enum Navigator {
4 | BLINK
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/FinalFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.Context
4 | import android.content.pm.ActivityInfo
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.activity.OnBackPressedCallback
10 | import androidx.fragment.app.Fragment
11 | import com.seewo.blink.annotation.BlinkUri
12 | import com.seewo.blink.example.Uris
13 | import com.seewo.blink.example.databinding.FragmentFinalBinding
14 | import com.seewo.blink.fragment.annotation.Orientation
15 | import com.seewo.blink.fragment.popTo
16 |
17 | @BlinkUri(Uris.FINAL_FRAGMENT)
18 | @Orientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
19 | class FinalFragment: Fragment() {
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View = FragmentFinalBinding.inflate(inflater, container, false).apply {
25 | next.setOnClickListener {
26 | // 直接回退到HomeFragment
27 | popTo("")
28 | }
29 | }.root
30 |
31 | override fun onAttach(context: Context) {
32 | super.onAttach(context)
33 | // 拦截返回键,直接回退到HomeFragment
34 | requireActivity().onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
35 | override fun handleOnBackPressed() {
36 | // 直接回退到HomeFragment
37 | popTo("")
38 | }
39 | })
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/FragmentContainerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import com.seewo.blink.example.fragment.interceptor.LoggerInterceptor
7 | import com.seewo.blink.fragment.attach
8 | import com.seewo.blink.fragment.container.BlinkContainerActivity
9 | import com.seewo.blink.fragment.detach
10 |
11 | class FragmentContainerActivity: BlinkContainerActivity() {
12 | companion object {
13 | @JvmStatic
14 | fun start(context: Context) {
15 | context.startActivity(Intent(context, FragmentContainerActivity::class.java))
16 | }
17 | }
18 |
19 | override fun startFragment() = HomeFragment()
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | LoggerInterceptor().attach()
23 | }
24 |
25 | override fun onDestroy() {
26 | super.onDestroy()
27 | LoggerInterceptor().detach()
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/HomeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.pm.ActivityInfo
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.ContextThemeWrapper
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.Toast
11 | import com.seewo.blink.annotation.BlinkUri
12 | import com.seewo.blink.example.R
13 | import com.seewo.blink.example.Uris
14 | import com.seewo.blink.example.bean.Navigator
15 | import com.seewo.blink.example.databinding.FragmentHomeBinding
16 | import com.seewo.blink.example.fragment.interceptor.ExampleInterceptor
17 | import com.seewo.blink.example.ktx.toast
18 | import com.seewo.blink.fragment.annotation.KeepAlive
19 | import com.seewo.blink.fragment.annotation.Orientation
20 | import com.seewo.blink.fragment.annotation.SystemUI
21 | import com.seewo.blink.fragment.attach
22 | import com.seewo.blink.fragment.blinking
23 | import com.seewo.blink.fragment.detach
24 | import com.seewo.blink.fragment.mode.SingleTaskFragment
25 | import com.seewo.blink.utils.append
26 | import com.seewo.blink.utils.buildUri
27 |
28 | @BlinkUri(Uris.FRAGMENT)
29 | @Orientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
30 | @SystemUI(brightnessLight = false)
31 | @KeepAlive
32 | class HomeFragment: SingleTaskFragment() {
33 | private val interceptor = ExampleInterceptor()
34 | override fun onCreateView(
35 | inflater: LayoutInflater,
36 | container: ViewGroup?,
37 | savedInstanceState: Bundle?
38 | ): View = FragmentHomeBinding.inflate(
39 | inflater.cloneInContext(
40 | ContextThemeWrapper(requireContext(), R.style.Theme_Blink)),
41 | container,
42 | false
43 | ).apply {
44 | next.setOnClickListener {
45 | blinking(Uris.NEXT_FRAGMENT, onIntercepted = {
46 | it ?: return@blinking
47 | Log.e("BLINK", it.message, it)
48 | Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
49 | })
50 | }
51 | interceptor.attach()
52 | deny.setOnCheckedChangeListener { _, checked ->
53 | if (checked) {
54 | interceptor.attach()
55 | } else {
56 | interceptor.detach()
57 | }
58 | }
59 | nextWithParam.setOnClickListener {
60 | blinking(Uris.RETURN_RESULT_FRAGMENT.buildUri {
61 | append("navigator", Navigator.BLINK)
62 | }) {
63 | if (it != null) {
64 | toast("返回结果: $it")
65 | } else {
66 | toast("返回结果: 无")
67 | }
68 | }
69 | }
70 | goToTemp.setOnClickListener {
71 | blinking(Uris.TEMP_FRAGMENT)
72 | }
73 | singleTop.setOnClickListener {
74 | blinking(Uris.SINGLE_TOP_FRAGMENT)
75 | }
76 | }.root.apply { setBackgroundResource(R.color.purple_500) }
77 |
78 | override fun onNewArguments(arguments: Bundle?) {
79 | toast("onNewArguments $arguments")
80 | Log.i("BLINK", "onNewArguments $arguments")
81 | }
82 |
83 | override fun onDestroy() {
84 | super.onDestroy()
85 | interceptor.detach()
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/NextFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.pm.ActivityInfo
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.fragment.app.Fragment
10 | import com.seewo.blink.annotation.BlinkUri
11 | import com.seewo.blink.example.Uris
12 | import com.seewo.blink.example.databinding.FragmentNextBinding
13 | import com.seewo.blink.example.fragment.interceptor.RedirectInterceptor
14 | import com.seewo.blink.example.ktx.toast
15 | import com.seewo.blink.fragment.annotation.CustomAnimations
16 | import com.seewo.blink.fragment.annotation.Orientation
17 | import com.seewo.blink.fragment.annotation.SystemUI
18 | import com.seewo.blink.fragment.attach
19 | import com.seewo.blink.fragment.blinking
20 | import com.seewo.blink.fragment.detach
21 |
22 | @BlinkUri(Uris.NEXT_FRAGMENT)
23 | @Orientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
24 | @SystemUI(brightnessLight = true, hideNavigationBar = true, hideStatusBar = true)
25 | @CustomAnimations
26 | class NextFragment: Fragment() {
27 | private val redirectInterceptor = RedirectInterceptor()
28 | override fun onCreateView(
29 | inflater: LayoutInflater,
30 | container: ViewGroup?,
31 | savedInstanceState: Bundle?
32 | ): View = FragmentNextBinding.inflate(inflater, container, false).apply {
33 | next.setOnClickListener {
34 | blinking(Uris.NOT_EXISTS, onIntercepted = {
35 | it ?: return@blinking
36 | Log.e("BLINK", it.message, it)
37 | toast(it.message)
38 | })
39 | }
40 | home.setOnCheckedChangeListener { _, checked ->
41 | if (checked) {
42 | redirectInterceptor.attach()
43 | } else {
44 | redirectInterceptor.detach()
45 | }
46 | }
47 | }.root
48 |
49 | override fun onDestroyView() {
50 | super.onDestroyView()
51 | redirectInterceptor.detach()
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/ReturnResultFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.pm.ActivityInfo
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import com.seewo.blink.annotation.BlinkUri
10 | import com.seewo.blink.example.Uris
11 | import com.seewo.blink.example.bean.Navigator
12 | import com.seewo.blink.example.databinding.FragmentReturnResultBinding
13 | import com.seewo.blink.fragment.annotation.CustomAnimations
14 | import com.seewo.blink.fragment.annotation.Orientation
15 | import com.seewo.blink.fragment.enumParams
16 | import com.seewo.blink.fragment.pop
17 |
18 | @BlinkUri(Uris.RETURN_RESULT_FRAGMENT)
19 | @Orientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
20 | @CustomAnimations
21 | class ReturnResultFragment: Fragment() {
22 | private val navigator by enumParams("navigator")
23 |
24 | override fun onCreateView(
25 | inflater: LayoutInflater,
26 | container: ViewGroup?,
27 | savedInstanceState: Bundle?
28 | ): View = FragmentReturnResultBinding.inflate(inflater, container, false).apply {
29 | params.text = "本页面为横屏\n欢迎使用: $navigator"
30 | result.setOnClickListener {
31 | pop(Bundle().apply {
32 | putString("result", "再见")
33 | })
34 | }
35 | finish.setOnClickListener {
36 | pop()
37 | }
38 | }.root
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/SingleTopFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.pm.ActivityInfo
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import com.seewo.blink.annotation.BlinkUri
10 | import com.seewo.blink.example.Uris
11 | import com.seewo.blink.example.databinding.FragmentTempBinding
12 | import com.seewo.blink.example.ktx.toast
13 | import com.seewo.blink.fragment.annotation.Orientation
14 | import com.seewo.blink.fragment.blinking
15 |
16 | @BlinkUri(Uris.SINGLE_TOP_FRAGMENT)
17 | @Orientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
18 | class SingleTopFragment: com.seewo.blink.fragment.mode.SingleTopFragment() {
19 | override fun onCreateView(
20 | inflater: LayoutInflater,
21 | container: ViewGroup?,
22 | savedInstanceState: Bundle?
23 | ): View = FragmentTempBinding.inflate(inflater, container, false).apply {
24 | text.text = "当前页面为SingleTop页面"
25 | next.text = "跳转到本页面"
26 | next.setOnClickListener {
27 | blinking(Uris.SINGLE_TOP_FRAGMENT)
28 | }
29 | }.root
30 |
31 | override fun onNewArguments(arguments: Bundle?) {
32 | super.onNewArguments(arguments)
33 | Log.e("BLINK", "onNewArguments >> arguments: $arguments")
34 | toast("onNewArguments >> arguments: $arguments")
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/TempFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment
2 |
3 | import android.content.pm.ActivityInfo
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import com.seewo.blink.annotation.BlinkUri
10 | import com.seewo.blink.example.Uris
11 | import com.seewo.blink.example.databinding.FragmentTempBinding
12 | import com.seewo.blink.fragment.R
13 | import com.seewo.blink.fragment.annotation.CustomAnimations
14 | import com.seewo.blink.fragment.annotation.Orientation
15 | import com.seewo.blink.fragment.blinking
16 |
17 | @BlinkUri(Uris.TEMP_FRAGMENT)
18 | @Orientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
19 | @CustomAnimations(
20 | enter = R.anim.enter_from_bottom, exit = R.anim.fade_out,
21 | popEnter = R.anim.fade_in, popExit = R.anim.exit_to_bottom)
22 | class TempFragment: Fragment() {
23 | override fun onCreateView(
24 | inflater: LayoutInflater,
25 | container: ViewGroup?,
26 | savedInstanceState: Bundle?
27 | ): View = FragmentTempBinding.inflate(inflater, container, false).apply {
28 | next.setOnClickListener {
29 | blinking(Uris.FINAL_FRAGMENT)
30 | }
31 | }.root
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/interceptor/ExampleInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment.interceptor
2 |
3 | import android.os.Bundle
4 | import androidx.core.net.toUri
5 | import androidx.fragment.app.Fragment
6 | import com.seewo.blink.example.Uris
7 | import com.seewo.blink.fragment.interrupt
8 | import com.seewo.blink.fragment.uriNonNull
9 |
10 | class ExampleInterceptor : com.seewo.blink.fragment.interceptor.AsyncInterceptor {
11 |
12 | override fun filter(target: Bundle) =
13 | target.uriNonNull.path == Uris.NEXT_FRAGMENT.toUri().path!!
14 |
15 | override suspend fun process(from: Fragment?, target: Bundle) {
16 | interrupt("拦截器: 禁止跳转")
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/interceptor/LoggerInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment.interceptor
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import androidx.fragment.app.Fragment
6 | import com.seewo.blink.fragment.generateFragmentTag
7 | import com.seewo.blink.fragment.interceptor.AsyncInterceptor
8 | import com.seewo.blink.fragment.uriNonNull
9 |
10 | class LoggerInterceptor: AsyncInterceptor {
11 |
12 | override suspend fun process(from: Fragment?, target: Bundle) {
13 | Log.i("fragment", "[from] ${from?.generateFragmentTag} [to] ${target.uriNonNull}")
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/fragment/interceptor/RedirectInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.fragment.interceptor
2 |
3 | import android.os.Bundle
4 | import androidx.core.net.toUri
5 | import androidx.fragment.app.Fragment
6 | import com.seewo.blink.example.Uris
7 | import com.seewo.blink.fragment.interceptor.AsyncInterceptor
8 | import com.seewo.blink.fragment.setUri
9 | import com.seewo.blink.fragment.uriNonNull
10 |
11 | class RedirectInterceptor: AsyncInterceptor {
12 | override fun filter(target: Bundle) =target.uriNonNull.path == Uris.NOT_EXISTS.toUri().path!!
13 |
14 | override fun priority() = 2
15 | override suspend fun process(from: Fragment?, target: Bundle) {
16 | target.setUri(Uris.FRAGMENT)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/blink/example/ktx/ToastKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.example.ktx
2 |
3 | import android.content.Context
4 | import android.widget.Toast
5 | import androidx.fragment.app.Fragment
6 |
7 | fun Context.toast(msg: String?) {
8 | msg ?: return
9 | Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
10 | }
11 |
12 | fun Fragment.toast(msg: String?) {
13 | msg ?: return
14 | Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
15 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/fragment_left_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fragment_left_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fragment_right_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fragment_right_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fragment_stay.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
23 |
24 |
29 |
30 |
39 |
40 |
41 |
42 |
47 |
48 |
53 |
54 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
29 |
30 |
41 |
42 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_next.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_return_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
30 |
31 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_final.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
31 |
32 |
37 |
38 |
44 |
45 |
54 |
55 |
56 |
57 |
62 |
63 |
69 |
70 |
77 |
78 |
79 |
80 |
85 |
86 |
92 |
93 |
100 |
101 |
102 |
103 |
108 |
109 |
115 |
116 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_next.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
31 |
32 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_return_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
30 |
31 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_temp.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/logo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/app/src/main/res/mipmap-xxxhdpi/logo.jpeg
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Blink
3 |
4 | blink
5 | navigator
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/blink-activity/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/blink-activity/README.md:
--------------------------------------------------------------------------------
1 | # Blink (Activity)
2 |
3 | ## 主要功能
4 |
5 | - Activity路由跳转并携带参数,返回路由结果
6 | - Activity数据返回回调(告别startActivityForResult)
7 | - 全局路由拦截器,可设置优先级,也可以动态添加和删除
8 |
9 | ## 解决一些第三方路由痛点
10 |
11 | 这里主要对标ARouter
12 |
13 | - ARouter
14 | - 功能包含了Activity的路由,以及全局拦截器,拦截器不支持动态增删
15 | - 也包含了Fragment和接口的依赖注入(对接口的依赖注入较简单粗暴,仅支持单例,无法自定义实现类的构造方法)
16 | - 使用注解,通过字节码插桩和apt的方式编译时生成代码来创建路由表,并在全局初始化时加载路由表,造成一定的编译时开销
17 |
18 | - Blink
19 | - 功能仅包含Activity路由和全局拦截器,拦截器支持动态增删,但包含了页面结果回调。
20 | - 对于依赖注入的场景建议引入专门的依赖注入框架,如koin等
21 | - 使用ksp处理注解,不引入gradle plugin,避免造成过多编译时开销
22 |
23 | ## 接入指南
24 |
25 | ### 1、依赖引入
26 |
27 | 最新版本:[](https://jitpack.io/#robin8yeung/Blink)
28 |
29 | ```groovy
30 | implementation "com.github.robin8yeung.Blink:blink-activity:$version"
31 | implementation "com.github.robin8yeung.Blink:blink-utils:$version"
32 | ksp "com.github.robin8yeung.Blink:blink-ksp:$version"
33 | ```
34 |
35 | ### 2、为页面定义路由uri
36 |
37 | #### uri
38 |
39 | 通过BlinkUri注解来定义页面路由uri。路由uri作为路由地址用于映射页面,发起路由时会从路由表中。
40 |
41 | #### 注意:路由表必须完成注入才能正常使用
42 |
43 | > 关于路由表注入请先了解 [blink-annotation](../blink-annotation/README.md)
44 |
45 | ```kotlin
46 | object Uris {
47 | const val activity = "blink://my.app/activity"
48 | const val HOME = "blink://my.app/home"
49 | }
50 |
51 | // 为MyActivity定义单个路由uri
52 | @BlinkUri(Uris.activity)
53 | class MyActivity : Activity() {
54 | // ....
55 | }
56 |
57 | // 为MyActivity定义多个路由uri
58 | @BlinkUri(value = [Uris.activity, Uris.HOME])
59 | class MyActivity : Activity() {
60 | // ....
61 | }
62 | ```
63 |
64 | ### 3、路由与传参
65 |
66 | 对于路由跳转,kotlin建议使用Context.blink扩展函数,java则使用Blink.navigation的静态方法
67 |
68 | > 如果需要对Uri进行复杂的参数设置,可以借助Uri.build()、String.buildUri()等扩展方法,
69 | > 详见 [blink-utils](../blink-utils/README.md)
70 |
71 | #### 异常处理
72 |
73 | kotlin中推荐使用扩展函数来调用,对于扩展函数的相关方法的返回为Result,可以从中获取路由结果。路由失败的原因主要有:
74 |
75 | - ActivityNotFoundException 无法找到uri对应的Activity
76 | - 自定义异常 被路由拦截,推荐在拦截器抛InterruptedException或其子类来进行路由拦截
77 |
78 | kotlin中使用
79 |
80 | ```kotlin
81 | context.blink("blink://navigator/example?name=Blink").onFailure {
82 | // 处理异常
83 | }.onSuccess {
84 | // 路由成功
85 | }
86 | ```
87 |
88 | 对于java中使用,提供了Blink为入口的静态方法。但需要注意的是,因为java不支持Result,所以对于Blink的静态方法,异常会直接抛出,如有需要,请务必在java业务端做try-catch
89 |
90 | java中使用
91 |
92 | ```java
93 | try {
94 | Blink.navigation(context,Uri.parse("blink://navigation/example?name=Hello"));
95 | } catch(Exception e){
96 | // 处理异常
97 | }
98 | ```
99 |
100 | ### 4、参数获取
101 |
102 | kotlin中实现参数获取
103 |
104 | ```kotlin
105 | import android.app.Activity
106 |
107 | @BlinkUri(Uris.activity)
108 | class ExampleActivity : Activity() {
109 | // 业务自行处理Name参数传入
110 | private val name: String? by lazy { intent.data?.getQueryParameter("name") }
111 |
112 | // 由Blink提供懒加载函数进行参数注入,默认值可选。仅用于Activity
113 | private val age: Int by intParams("age", 18)
114 | }
115 | ```
116 |
117 | java中实现参数注入推荐使用BlinkParams注解配合Blink.inject()方法。
118 |
119 | 特别注意:注意这个方法对于Activity和Fragment具有不同的实现。Fragment仅用于ARouter老项目迁移,不推荐使用。
120 |
121 | - 对于Activity的注入,主要从intent.data,即uri中去获取传入的参数,支持的类型较少
122 | - 对于Fragment的注入,主要从arguments,即Bundle中去获取传入的参数,支持的类型较多(但也不是支持Bundle的全部类型,详见源码)
123 |
124 | ```java
125 | import android.app.Activity;
126 |
127 | import com.seewo.blink.BlinkParams;
128 | import com.seewo.blink.Blink;
129 |
130 | @BlinkUri(Uris.activity)
131 | public class ExampleActivity extends Activity {
132 | @BlinkParams(name = "name")
133 | private String name;
134 |
135 | @BlinkParams(name = "age")
136 | private int age = 18;
137 |
138 | @Override
139 | protected void onCreate(Bundle savedInstanceState) {
140 | super.onCreate(savedInstanceState);
141 | // 执行参数注入
142 | Blink.inject(this);
143 | }
144 | }
145 | ```
146 |
147 | ```java
148 | import androidx.fragment.app.Fragment;
149 |
150 | import com.seewo.blink.BlinkParams;
151 | import com.seewo.blink.Blink;
152 |
153 | // 对于Fragment
154 | public class ExampleFragment extends Fragment {
155 | @BlinkParams(name = "name")
156 | private String name;
157 |
158 | @BlinkParams(name = "age")
159 | private int age = 18;
160 |
161 | @Override
162 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
163 | // 执行参数注入
164 | Blink.inject(this);
165 | return new YourView(inflater, container, savedInstanceState);
166 | }
167 | }
168 | ```
169 |
170 | ### 5、增删拦截器
171 |
172 | kotlin中使用
173 |
174 | ```kotlin
175 | // 这里仅用于举例,真实使用时,建议拦截器职责单一
176 | class LoggerInterceptor : AsyncInterceptor {
177 | override suspend fun process(context: Context, intent: Intent) {
178 | // 打印路由信息
179 | FLog.a("from $context to $intent data: ${intent.dataString}")
180 | // 获取路由请求的参数,修改path并增加参数
181 | val uri = intent.data
182 | intent.data = uri?.build {
183 | path("/another")
184 | append("new", true)
185 | }
186 | // 对于缺少权限的情况,拦截跳转
187 | if (!Permission.hasCameraPermission) {
188 | interrupt("缺少必要权限")
189 | }
190 | }
191 | }
192 |
193 | val loggerInterceptor = LoggerInterceptor()
194 |
195 | // 添加拦截器
196 | loggerInterceptor.attach()
197 | // 移除拦截器
198 | loggerInterceptor.detach()
199 | ```
200 |
201 | java中使用
202 |
203 | ```java
204 | LoggerInterceptor loggerInterceptor = new LoggerInterceptor();
205 | // 添加拦截器
206 | Blink.add(loggerInterceptor);
207 | // 移除拦截器
208 | Blink.remove(loggerInterceptor);
209 | ```
210 |
211 | ### 6、结果回调
212 |
213 | ```kotlin
214 | import android.app.Activity
215 |
216 | class PrevActivity : Activity() {
217 |
218 | override fun onCreate(savedInstanceState: Bundle?) {
219 | super.onCreate(savedInstanceState)
220 | setContentView(R.layout.example)
221 | findViewById(R.id.button).setOnClickListener {
222 | // 跳转至EXAMPLE_2
223 | blinking(Uris.EXAMPLE_2, onIntercepted = {
224 | if (it != null) {
225 | // 路由如果存在异常
226 | Log.e("BLINK", it.message, it)
227 | Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show()
228 | }
229 | }) {
230 | // ActivityResult回调
231 | if (it.resultCode == Activity.RESULT_OK) {
232 | Toast.makeText(this, "Return result: ${it.data}", Toast.LENGTH_LONG).show()
233 | } else {
234 | Toast.makeText(this, "Return result: Cancel", Toast.LENGTH_LONG).show()
235 | }
236 | }
237 | }
238 | }
239 | }
240 |
241 | class NextActivity : Activity() {
242 | private val name: String? by lazy { intent.data?.getQueryParameter("name") }
243 |
244 | override fun onCreate(savedInstanceState: Bundle?) {
245 | super.onCreate(savedInstanceState)
246 | setContentView(R.layout.example)
247 | findViewById(R.id.button).setOnClickListener {
248 | // 点击按钮,返回成功结果
249 | setResult(Activity.RESULT_OK, Intent().apply {
250 | putExtra("result", "ok")
251 | })
252 | finish()
253 | }
254 | }
255 | }
256 | ```
257 |
258 | ## 特别关注
259 |
260 | 对于弹窗拦截等场景,如果遇到异步操作使用了回调的返回方式,可以借助suspendCancellableCoroutine函数,将回调转为协程的方式,以便在拦截器中进行处理。
261 |
262 | ```kotlin
263 | class PluginInterceptor : AsyncInterceptor {
264 | private val caredPath = Uris.PLUGIN.toUri().path
265 |
266 | // 仅对plugin的path生效
267 | override fun filter(intent: Intent) =
268 | intent.data?.path == caredPath
269 |
270 | // 设置拦截器优先级
271 | override fun priority() = -2
272 |
273 | override suspend fun process(context: Context, intent: Intent) {
274 | val activity = context as? Activity
275 | when {
276 | Build.VERSION.SDK_INT < 29 -> {
277 | // 可以抛不同的异常,来在路由调用端针对不同的异常进行提示。此处举例不涉及
278 | interrupt("系统版本过低")
279 | }
280 | !PluginConfig.isPluginEnable -> {
281 | interrupt("用户无权限")
282 | }
283 | else -> {
284 | activity?.let {
285 | runCatching {
286 | // 回调转协程
287 | suspendCancellableCoroutine { con ->
288 | Dialog.loadPluginWithDialog(
289 | activity, ResourceTag.plugin
290 | ) {
291 | if (it != null) {
292 | con.resumeWithException(it)
293 | } else {
294 | con.resume(Unit)
295 | }
296 | }
297 | }
298 | }.onFailure {
299 | FLog.e(it)
300 | interrupt("插件未成功安装")
301 | }
302 | }
303 | }
304 | }
305 | }
306 | }
307 | ```
308 |
--------------------------------------------------------------------------------
/blink-activity/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | if (LOCAL_DEBUG.toBoolean()) {
7 | apply from: "${project.rootDir}/gradle/local-maven-push.gradle"
8 | } else {
9 | apply from: "${project.rootDir}/gradle/jitpack-push.gradle"
10 | // apply from: "${project.rootDir}/gradle/jfrog-push.gradle"
11 | }
12 |
13 | android {
14 | namespace 'com.seewo.blink'
15 | compileSdk 33
16 |
17 | defaultConfig {
18 | minSdk 21
19 | targetSdk 28
20 |
21 | consumerProguardFiles "consumer-rules.pro"
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = '1.8'
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation 'androidx.appcompat:appcompat:1.6.1'
41 | implementation "androidx.startup:startup-runtime:1.1.1"
42 | api project(":blink-utils")
43 | api project(":blink-annotation")
44 | }
--------------------------------------------------------------------------------
/blink-activity/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/blink-activity/consumer-rules.pro
--------------------------------------------------------------------------------
/blink-activity/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=blink-activity
2 | POM_NAME=blink-activity
3 | POM_DESCRIPTION=Blink navigator
--------------------------------------------------------------------------------
/blink-activity/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/blink-activity/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/BlinkInitializer.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | class BlinkInitializer : Initializer{
7 | override fun create(context: Context) {
8 | Blink.init(context)
9 | }
10 |
11 | override fun dependencies(): MutableList>> = mutableListOf()
12 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/BlinkKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.net.Uri
7 | import androidx.activity.result.ActivityResult
8 | import androidx.activity.result.ActivityResultCallback
9 | import androidx.core.app.ActivityOptionsCompat
10 | import androidx.core.net.toUri
11 | import androidx.fragment.app.Fragment
12 | import com.seewo.blink.interceptor.BaseInterceptor
13 | import com.seewo.blink.interceptor.Interceptor
14 | import com.seewo.blink.interceptor.InterruptedException
15 | import kotlinx.coroutines.MainScope
16 | import kotlinx.coroutines.launch
17 |
18 |
19 | /**
20 | * 添加拦截器
21 | */
22 | fun BaseInterceptor.attach() {
23 | Blink.add(this)
24 | }
25 |
26 | /**
27 | * 移除拦截器
28 | */
29 | fun BaseInterceptor.detach() {
30 | Blink.remove(this)
31 | }
32 |
33 | /**
34 | * 通过uri创建Blink使用的Intent
35 | */
36 | fun Uri.createBlinkIntent() = Blink.createIntent(this)
37 |
38 | /**
39 | * 通过uri string创建Blink使用的Intent
40 | */
41 | fun String.createBlinkIntent() = toUri().createBlinkIntent()
42 |
43 | /**
44 | * @param uri 字符串类型的Uri
45 | * @param options 控制跳转动画
46 | * @param onResult ActivityResult回调。
47 | * 注意:对于Context不是FragmentActivity的情况设置回调,可能会导致共享元素动画异常
48 | * @return 执行结果,可能存在以下两种异常
49 | * - ActivityNotFoundException 无法找到uri对应的Activity
50 | * - 自定义异常 路由被拦截
51 | */
52 | @Deprecated("use Context.blinking() instead")
53 | fun Context.blink(
54 | uri: String,
55 | options: ActivityOptionsCompat? = null,
56 | onResult: ActivityResultCallback? = null
57 | ): Result = kotlin.runCatching { Blink.navigationForResult(this, uri, options, onResult) }
58 |
59 | /**
60 | * @param uri Uri类型的Uri
61 | * @param options 控制跳转动画
62 | * @param onResult ActivityResult回调。
63 | * 注意:对于Context不是FragmentActivity的情况设置回调,可能会导致共享元素动画异常
64 | * @return 执行结果,可能存在以下两种异常
65 | * - ActivityNotFoundException 无法找到uri对应的Activity
66 | * - 自定义异常 路由被拦截
67 | */
68 | @Deprecated("use Context.blinking() instead")
69 | fun Context.blink(
70 | uri: Uri,
71 | options: ActivityOptionsCompat? = null,
72 | onResult: ActivityResultCallback? = null
73 | ): Result = kotlin.runCatching { Blink.navigationForResult(this, uri, options, onResult) }
74 |
75 | /**
76 | * @param intent 建议使用 Uri.createIntent()方法来创建Intent
77 | * @param options 控制跳转动画
78 | * @param onResult ActivityResult回调。
79 | * 注意:对于Context不是FragmentActivity的情况设置回调,可能会导致共享元素动画异常
80 | * @return 执行结果,可能存在以下两种异常
81 | * - ActivityNotFoundException 无法找到uri对应的Activity
82 | * - NavigationInterruptedException 路由被拦截
83 | * @see createBlinkIntent
84 | */
85 | @Deprecated("use Context.blinking() instead")
86 | fun Context.blink(
87 | intent: Intent,
88 | options: ActivityOptionsCompat? = null,
89 | onResult: ActivityResultCallback? = null
90 | ): Result = kotlin.runCatching { Blink.navigationForResult(this, intent, options, onResult) }
91 |
92 | /**
93 | * 异步执行,路由导航
94 | * @param uri 字符串类型的Uri
95 | * @param options 控制跳转动画
96 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
97 | * @param onResult ActivityResult回调。
98 | * 注意:对于Context不是FragmentActivity的情况设置回调,可能会导致共享元素动画异常
99 | * @return 执行结果,可能存在以下两种异常
100 | * - ActivityNotFoundException 无法找到uri对应的Activity
101 | * - 自定义异常 路由被拦截
102 | */
103 | fun Context.blinking(
104 | uri: String,
105 | options: ActivityOptionsCompat? = null,
106 | onIntercepted: ((Throwable?) -> Unit)? = null,
107 | onResult: ActivityResultCallback? = null
108 | ) = blinking(Uri.parse(uri), options, onIntercepted, onResult)
109 |
110 | /**
111 | * 异步执行,路由导航
112 | * @param uri Uri类型的Uri
113 | * @param options 控制跳转动画
114 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
115 | * @param onResult ActivityResult回调。
116 | * 注意:对于Context不是FragmentActivity的情况设置回调,可能会导致共享元素动画异常
117 | * @return 执行结果,可能存在以下两种异常
118 | * - ActivityNotFoundException 无法找到uri对应的Activity
119 | * - 自定义异常 路由被拦截
120 | */
121 | fun Context.blinking(
122 | uri: Uri,
123 | options: ActivityOptionsCompat? = null,
124 | onIntercepted: ((Throwable?) -> Unit)? = null,
125 | onResult: ActivityResultCallback? = null
126 | ) = blinking(Blink.createIntent(uri), options, onIntercepted, onResult)
127 |
128 | /**
129 | * 异步执行,路由导航
130 | * @param intent 建议使用 Uri.createIntent()方法来创建Intent
131 | * @param options 控制跳转动画
132 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
133 | * @param onResult ActivityResult回调。
134 | * 注意:对于Context不是FragmentActivity的情况设置回调,可能会导致共享元素动画异常
135 | * @return 执行结果,可能存在以下两种异常
136 | * - ActivityNotFoundException 无法找到uri对应的Activity
137 | * - NavigationInterruptedException 路由被拦截
138 | * @see createBlinkIntent
139 | */
140 | fun Context.blinking(
141 | intent: Intent,
142 | options: ActivityOptionsCompat? = null,
143 | onIntercepted: ((Throwable?) -> Unit)? = null,
144 | onResult: ActivityResultCallback? = null
145 | ) {
146 | MainScope().launch {
147 | kotlin.runCatching {
148 | Blink.asyncNavigationForResult(this@blinking, intent, options, onResult)
149 | }.apply {
150 | onIntercepted?.invoke(exceptionOrNull())
151 | }
152 | }
153 | }
154 |
155 | /**
156 | * 拦截器拦截路由,建议抛出以下异常
157 | */
158 | fun BaseInterceptor.interrupt(msg: String? = null) {
159 | throw InterruptedException(this, msg)
160 | }
161 |
162 | fun Activity.stringParams(name: String): Lazy = lazy {
163 | intent.data?.getQueryParameter(name)
164 | }
165 |
166 | fun Activity.stringParamsNonNull(name: String): Lazy = lazy {
167 | intent.data?.getQueryParameter(name) ?: ""
168 | }
169 |
170 | fun Activity.stringsParams(name: String): Lazy?> = lazy {
171 | intent.data?.getQueryParameters(name)
172 | }
173 |
174 | fun Activity.stringsParamsNonNull(name: String): Lazy> = lazy {
175 | intent.data?.getQueryParameters(name) ?: listOf()
176 | }
177 |
178 | fun Activity.boolParams(name: String, default: Boolean = false): Lazy = lazy {
179 | intent.data?.getBooleanQueryParameter(name, default) ?: default
180 | }
181 |
182 | fun Activity.intParams(name: String, default: Int = 0): Lazy = lazy {
183 | intent.data?.getQueryParameter(name)?.toIntOrNull() ?: default
184 | }
185 |
186 | fun Activity.longParams(name: String, default: Long = 0L): Lazy = lazy {
187 | intent.data?.getQueryParameter(name)?.toLongOrNull() ?: default
188 | }
189 |
190 | fun Activity.floatParams(name: String, default: Float = 0f): Lazy = lazy {
191 | intent.data?.getQueryParameter(name)?.toFloatOrNull() ?: default
192 | }
193 |
194 | fun Activity.doubleParams(name: String, default: Double = 0.0): Lazy = lazy {
195 | intent.data?.getQueryParameter(name)?.toDoubleOrNull() ?: default
196 | }
197 |
198 | inline fun Activity.enumParams(name: String): Lazy = lazy {
199 | if (T::class.java.isEnum) {
200 | val value = intent.data?.getQueryParameter(name)
201 | val valueInt = value?.toIntOrNull()
202 | if (valueInt != null) {
203 | T::class.java.runCatching { enumConstants!![valueInt] }.getOrNull()
204 | } else if (value != null) {
205 | T::class.java.runCatching {
206 | getMethod("valueOf", String::class.java).invoke(
207 | null,
208 | value
209 | )
210 | }.getOrNull() as T?
211 | } else null
212 | } else null
213 | }
214 |
215 | fun Fragment.stringParams(name: String): Lazy = lazy {
216 | arguments?.getString(name)
217 | }
218 |
219 | fun Fragment.stringsParams(name: String): Lazy?> = lazy {
220 | arguments?.getStringArrayList(name)
221 | }
222 |
223 | fun Fragment.boolParams(name: String, default: Boolean = false): Lazy = lazy {
224 | arguments?.getBoolean(name, default) ?: default
225 | }
226 |
227 | fun Fragment.intParams(name: String, default: Int = 0): Lazy = lazy {
228 | arguments?.getInt(name, default) ?: default
229 | }
230 |
231 | fun Fragment.longParams(name: String, default: Long = 0L): Lazy = lazy {
232 | arguments?.getLong(name, default) ?: default
233 | }
234 |
235 | fun Fragment.floatParams(name: String, default: Float = 0f): Lazy = lazy {
236 | arguments?.getFloat(name, default) ?: default
237 | }
238 |
239 | fun Fragment.doubleParams(name: String, default: Double = 0.0): Lazy = lazy {
240 | arguments?.getDouble(name, default) ?: default
241 | }
242 |
243 | inline fun Fragment.enumParams(name: String): Lazy = lazy {
244 | if (T::class.java.isEnum) {
245 | val valueInt = arguments?.runCatching { getInt(name) }?.getOrNull()
246 | val value = arguments?.getString(name)
247 | if (valueInt != null) {
248 | T::class.java.runCatching { enumConstants!![valueInt] }.getOrNull()
249 | } else if (value != null) {
250 | T::class.java.runCatching {
251 | getMethod("valueOf", String::class.java).invoke(
252 | null,
253 | value
254 | )
255 | }.getOrNull() as T?
256 | } else null
257 | } else null
258 | }
259 |
260 | fun Interceptor.putInGreenChannel(intent: Intent) = Blink.greenChannel(this, intent)
261 |
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/BlinkParams.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | @Target(AnnotationTarget.FIELD)
4 | annotation class BlinkParams(val name: String)
5 |
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/RouteMap.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.net.Uri
6 | import androidx.core.net.toUri
7 | import com.seewo.blink.utils.baseUri
8 | import java.util.concurrent.ConcurrentHashMap
9 |
10 | /**
11 | * 路由表,可手动注册,也可通过ksp动态注册
12 | */
13 | object RouteMap {
14 | private val routeMetadataMap = ConcurrentHashMap>()
15 |
16 | fun register(baseUri: String, activity: Class) {
17 | val confirmedBaseUri = baseUri.baseUri
18 | routeMetadataMap[confirmedBaseUri] = activity
19 | }
20 |
21 | fun get(uri: String): Intent = get(uri.toUri())
22 |
23 | fun get(uri: Uri): Intent = routeMetadataMap[uri.baseUri]?.let {
24 | Intent(Blink.context, it).apply {
25 | data = uri
26 | }
27 | } ?: Intent("action.Blink.ActivityNotFound", uri)
28 |
29 | fun dump(): Map> = routeMetadataMap
30 | }
31 |
32 | private val String.baseUri: String
33 | get() = split("?").first()
34 |
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/callback/UriBuilder.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.callback;
2 |
3 | import android.net.Uri;
4 |
5 | public interface UriBuilder {
6 | void build(Uri.Builder builder);
7 | }
8 |
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/interceptor/AsyncInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.interceptor
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 |
6 | interface AsyncInterceptor: BaseInterceptor {
7 | /**
8 | * 拦截器处理函数,如果需要拦截路由,可以抛异常,异常可以自定义
9 | *
10 | * @throws InterruptedException 建议拦截路由抛这个异常
11 | */
12 | @kotlin.jvm.Throws(InterruptedException::class)
13 | suspend fun process(context: Context, intent: Intent)
14 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/interceptor/BaseInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.interceptor
2 |
3 | import android.content.Intent
4 |
5 | interface BaseInterceptor {
6 | /**
7 | * 过滤器
8 | * @return 仅在函数返回true时,过滤器生效。默认不过滤。
9 | */
10 | fun filter(intent: Intent): Boolean = true
11 | /**
12 | * 优先级:数字大的优先级高,允许负数
13 | */
14 | fun priority(): Int = 0
15 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/interceptor/Interceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.interceptor
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 |
6 | @Deprecated("use AsyncInterceptor instead")
7 | interface Interceptor: BaseInterceptor {
8 | /**
9 | * 拦截器处理函数,如果需要拦截路由,可以抛异常,异常可以自定义
10 | *
11 | * @throws InterruptedException 建议拦截路由抛这个异常
12 | */
13 | @kotlin.jvm.Throws(InterruptedException::class)
14 | fun process(context: Context, intent: Intent)
15 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/interceptor/Interceptors.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.interceptor
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import com.seewo.blink.Blink
6 |
7 | internal class Interceptors {
8 | private val interceptors = mutableListOf()
9 |
10 | @Synchronized
11 | fun add(interceptor: BaseInterceptor) {
12 | if (interceptors.contains(interceptor)) return
13 | interceptors += interceptor
14 | interceptors.sortByDescending { it.priority() }
15 | }
16 |
17 | @Synchronized
18 | fun remove(interceptor: BaseInterceptor) {
19 | interceptors.remove(interceptor)
20 | }
21 |
22 | suspend fun process(context: Context, intent: Intent) {
23 | interceptors.filter {
24 | !intent.isInGreenChannel(it) && it.filter(intent)
25 | }.forEach {
26 | if (it is Interceptor) {
27 | it.process(context, intent)
28 | } else if (it is AsyncInterceptor) {
29 | it.process(context, intent)
30 | }
31 | }
32 | }
33 |
34 | private fun Intent.isInGreenChannel(interceptor: BaseInterceptor): Boolean =
35 | getSerializableExtra(Blink.GREEN_CHANNEL) == interceptor::class.java
36 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/interceptor/InterruptedException.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.interceptor
2 |
3 | open class InterruptedException(
4 | val interceptor: BaseInterceptor, msg: String? = null
5 | ): RuntimeException("Interrupted By ${interceptor::class.java.simpleName} $msg")
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/stub/ResultHolder.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.stub
2 |
3 | import android.app.Activity
4 | import android.content.ActivityNotFoundException
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.content.pm.PackageManager
8 | import android.os.Bundle
9 | import androidx.activity.result.ActivityResult
10 | import androidx.activity.result.ActivityResultCallback
11 | import androidx.core.app.ActivityOptionsCompat
12 | import androidx.fragment.app.FragmentActivity
13 | import kotlin.random.Random
14 |
15 | internal object ResultHolder {
16 | const val REQUEST_CODE = "Blink.RequestCode"
17 |
18 | val resultMap = mutableMapOf()
19 | private val random = Random.Default
20 |
21 | fun launch(
22 | context: Context,
23 | intent: Intent,
24 | options: ActivityOptionsCompat?,
25 | onResult: ActivityResultCallback
26 | ) {
27 | val requestCode = random.nextInt(1, Int.MAX_VALUE)
28 | kotlin.runCatching {
29 | if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) == null) {
30 | throw ActivityNotFoundException("No Activity found to handle $intent")
31 | }
32 |
33 | context.startActivity(Intent(context, StubActivity::class.java).apply {
34 | if (context !is Activity) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
35 | resultMap[requestCode] = StubData(intent, options, onResult)
36 | putExtra(REQUEST_CODE, requestCode)
37 | })
38 | }.apply {
39 | exceptionOrNull()?.let {
40 | resultMap.remove(requestCode)
41 | throw it
42 | }
43 | }
44 | }
45 |
46 | fun launchWithFragment(
47 | context: FragmentActivity,
48 | intent: Intent,
49 | options: ActivityOptionsCompat?,
50 | onResult: ActivityResultCallback
51 | ) {
52 | val requestCode = random.nextInt(1, Int.MAX_VALUE)
53 | kotlin.runCatching {
54 | if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) == null) {
55 | throw ActivityNotFoundException("No Activity found to handle $intent")
56 | }
57 | context.supportFragmentManager.apply {
58 | beginTransaction().add(StubFragment().apply {
59 | resultMap[requestCode] = StubData(intent, options, onResult)
60 | arguments = Bundle().apply {
61 | putInt(REQUEST_CODE, requestCode)
62 | }
63 | }, StubFragment.TAG).commit()
64 | }
65 |
66 | }.apply {
67 | exceptionOrNull()?.let {
68 | resultMap.remove(requestCode)
69 | context.supportFragmentManager.findFragmentByTag(StubFragment.TAG)?.runCatching {
70 | context.supportFragmentManager.beginTransaction().remove(this).commit()
71 | }
72 | throw it
73 | }
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/stub/StubActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.stub
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.result.ActivityResult
7 |
8 | class StubActivity : Activity() {
9 | private val requestCode: Int by lazy { intent.getIntExtra(ResultHolder.REQUEST_CODE, 0) }
10 | private val stubData: StubData? by lazy { ResultHolder.resultMap.remove(requestCode) }
11 |
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | overridePendingTransition(0, 0)
14 | super.onCreate(savedInstanceState)
15 | setStatusBarTransparent(true)
16 | val data = this.stubData
17 | if (data == null) {
18 | finish()
19 | } else {
20 | startActivityForResult(data.intent, requestCode, data.options?.toBundle())
21 | }
22 | }
23 |
24 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
25 | if (requestCode == this.requestCode) {
26 | stubData?.callback?.onActivityResult(ActivityResult(resultCode, data))
27 | finish()
28 | }
29 | }
30 |
31 | override fun finish() {
32 | super.finish()
33 | overridePendingTransition(0, 0)
34 | }
35 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/stub/StubData.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.stub
2 |
3 | import android.content.Intent
4 | import androidx.activity.result.ActivityResult
5 | import androidx.activity.result.ActivityResultCallback
6 | import androidx.core.app.ActivityOptionsCompat
7 |
8 | class StubData(
9 | val intent: Intent,
10 | val options: ActivityOptionsCompat?,
11 | val callback: ActivityResultCallback
12 | )
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/stub/StubFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.stub
2 |
3 | import android.os.Bundle
4 | import androidx.activity.result.contract.ActivityResultContracts
5 | import androidx.fragment.app.Fragment
6 |
7 | class StubFragment : Fragment() {
8 | private val requestCode: Int by lazy { arguments?.getInt(ResultHolder.REQUEST_CODE) ?: 0 }
9 | private val stubData: StubData? by lazy { ResultHolder.resultMap.remove(requestCode) }
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | val stubData = stubData
14 | if (stubData == null) {
15 | finish()
16 | return
17 | }
18 | registerForActivityResult(
19 | ActivityResultContracts.StartActivityForResult(),
20 | ) {
21 | stubData.callback.onActivityResult(it)
22 | finish()
23 | }.launch(stubData.intent, stubData.options)
24 | }
25 |
26 | private fun finish() {
27 | parentFragmentManager.run {
28 | beginTransaction().remove(this@StubFragment).commit()
29 | }
30 | }
31 |
32 | companion object {
33 | const val TAG = "Blink.StubFragment"
34 | }
35 | }
--------------------------------------------------------------------------------
/blink-activity/src/main/java/com/seewo/blink/stub/UtilKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.stub
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.graphics.Color
6 | import android.os.Build
7 | import android.view.View
8 | import android.view.Window
9 | import android.view.WindowManager
10 |
11 |
12 | internal fun Activity.setStatusBarTransparent(lightStatusBar: Boolean) {
13 | if (miuiSetStatusBarLightMode(this, lightStatusBar)) {
14 | // Do nothing
15 | } else if (flymeSetStatusBarLightMode(this, lightStatusBar)) {
16 | // Do nothing
17 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
18 | setStatusBarTransparentWithSys(this, lightStatusBar)
19 | }
20 | setNavigationBarBtnColor(window, lightStatusBar)
21 | }
22 |
23 | private fun setStatusBarTransparentWithSys(activity: Activity, lightStatusBar: Boolean) {
24 | val window = activity.window
25 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
26 | if (lightStatusBar) {
27 | window.decorView.systemUiVisibility =
28 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
29 | } else {
30 | window.decorView.systemUiVisibility =
31 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
32 | }
33 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
34 | window.statusBarColor = Color.TRANSPARENT
35 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
36 | if (lightStatusBar) {
37 | window.navigationBarColor = Color.TRANSPARENT
38 | } else {
39 | window.navigationBarColor = Color.BLACK
40 | }
41 | }
42 | }
43 |
44 | /**
45 | * 设置状态栏图标为深色和魅族特定的文字风格,Flyme4.0以上
46 | * 可以用来判断是否为Flyme用户
47 | *
48 | * @param dark 是否把状态栏字体及图标颜色设置为深色
49 | * @return boolean 成功执行返回true
50 | */
51 | private fun flymeSetStatusBarLightMode(activity: Activity, dark: Boolean): Boolean {
52 | var result = false
53 | val window = activity.window
54 | if (window != null) {
55 | try {
56 | val lp = window.attributes
57 | val darkFlag = WindowManager.LayoutParams::class.java
58 | .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON")
59 | val meizuFlags = WindowManager.LayoutParams::class.java
60 | .getDeclaredField("meizuFlags")
61 | darkFlag.isAccessible = true
62 | meizuFlags.isAccessible = true
63 | val bit = darkFlag.getInt(null)
64 | var value = meizuFlags.getInt(lp)
65 | value = if (dark) {
66 | value or bit
67 | } else {
68 | value and bit.inv()
69 | }
70 | meizuFlags.setInt(lp, value)
71 | window.attributes = lp
72 | result = true
73 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
74 | // 新版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
75 | setStatusBarTransparentWithSys(activity, dark)
76 | }
77 | } catch (e: Exception) {
78 | // ignore
79 | }
80 | }
81 | return result
82 | }
83 |
84 | /**
85 | * 需要MIUIV6以上
86 | *
87 | * @param dark 是否把状态栏文字及图标颜色设置为深色
88 | * @return boolean 成功执行返回true
89 | */
90 | private fun miuiSetStatusBarLightMode(activity: Activity, dark: Boolean): Boolean {
91 | var result = false
92 | val window = activity.window
93 | if (window != null) {
94 | val clazz: Class<*> = window.javaClass
95 | try {
96 | var darkModeFlag = 0
97 | @SuppressLint("PrivateApi") val layoutParams =
98 | Class.forName("android.view.MiuiWindowManager\$LayoutParams")
99 | val field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE")
100 | darkModeFlag = field.getInt(layoutParams)
101 | val extraFlagField = clazz.getMethod(
102 | "setExtraFlags",
103 | Int::class.javaPrimitiveType,
104 | Int::class.javaPrimitiveType
105 | )
106 | if (dark) {
107 | extraFlagField.invoke(window, darkModeFlag, darkModeFlag) //状态栏透明且黑色字体
108 | } else {
109 | extraFlagField.invoke(window, 0, darkModeFlag) //清除黑色字体
110 | }
111 | result = true
112 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
113 | //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
114 | setStatusBarTransparentWithSys(activity, dark)
115 | }
116 | } catch (e: Exception) {
117 | // ignore
118 | }
119 | }
120 | return result
121 | }
122 |
123 | private fun setNavigationBarBtnColor(window: Window, light: Boolean) {
124 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
125 | val decorView = window.decorView
126 | var systemUiVisibility = decorView.systemUiVisibility
127 | systemUiVisibility =
128 | if (light) systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR else systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
129 | decorView.systemUiVisibility = systemUiVisibility
130 | }
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/blink-activity/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/blink-annotation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/blink-annotation/README.md:
--------------------------------------------------------------------------------
1 | # blink-annotation
2 |
3 | Blink提供了通过注解来声明页面路由的方式,通过ksp处理注解信息来为app生成路由表以及每个module的路由表初始化接口
4 |
5 | ## 注解概念
6 |
7 | ### BlinkUri
8 |
9 | 声明页面的路由地址,即uri,这里的uri应该是一个包含完整scheme,host和path,但不包含参数的uri,如"scheme://my.host/path"
10 | 值得注意的是,页面对应的uri可以是一个,也可以是多个。被注解的对象只能是Activity或Fragment的子类,否则将不会被blink-ksp处理
11 |
12 | ### BlinkMetadata
13 |
14 | 由于ksp生效的范围是单个module,每个module都需要对blink-ksp生成的路由表进行初始化。
15 | 我们没有选择通过Gradle plugin的transform来进行初始化,主要考虑这个操作是个低频的操作,而transform在方便的同时也会带来编译时的开销
16 | 所以和koin类似,选择了通过ksp生成简单的初始化接口,由开发者在每个模块中进行初始化(推荐使用Jetpack-startup),或者在Application中,逐一对各个模块进行初始化
17 |
18 | ## 使用示例
19 |
20 | #### 依赖引入
21 |
22 | blink-annotation不需要单独引入,blink-activity和blink-fragment都包含了相关依赖
23 | 由于ksp的生效范围是module,所以【每一个】使用过blink-annotation的【module】都需要引入blink-ksp来处理这些注解
24 |
25 | - 最新版本:[](https://jitpack.io/#robin8yeung/Blink)
26 |
27 | ```groovy
28 | ksp "com.github.robin8yeung.Blink:blink-ksp:$version"
29 | ```
30 |
31 | #### 实际使用
32 |
33 | 路由uri定义
34 |
35 | ```kotlin
36 | // 为MyFragment定义一个路由uri
37 | @BlinkUri(Uris.fragment)
38 | class MyFragment: Fragment() {
39 | // ....
40 | }
41 |
42 | // 为MyActivity定义多个路由uri
43 | @BlinkUri(value = [ Uris.activity, Uris.HOME ])
44 | class MyActivity: Activity() {
45 | // ....
46 | }
47 | ```
48 |
49 | 路由表注入入口定义和实现module路由表的注入
50 |
51 | ```kotlin
52 | // 用@BlinkMetadata注解定义一个路由表的初始化入口,为了简化调用,请继承BaseMetadata
53 | @BlinkMetadata
54 | class RouteMetadata : BaseMetadata()
55 |
56 | // lib module建议用startup框架来实现初始化,也可以在Application的onCreate中对所有模块的BaseMetadata子类进行初始化调用
57 | class AvatarInitializer : Initializer{
58 | override fun create(context: Context) {
59 | // 初始化,注入module的路由表,建立uri与页面的映射关系,否则无法实现路由跳转
60 | RouteMetadata().inject()
61 | }
62 |
63 | override fun dependencies(): MutableList>> =
64 | mutableListOf()
65 | }
66 | ```
--------------------------------------------------------------------------------
/blink-annotation/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'org.jetbrains.kotlin.jvm'
4 | }
5 |
6 | if (LOCAL_DEBUG.toBoolean()) {
7 | apply from: "${project.rootDir}/gradle/local-maven-push.gradle"
8 | } else {
9 | apply from: "${project.rootDir}/gradle/jitpack-push-java.gradle"
10 | // apply from: "${project.rootDir}/gradle/jfrog-push-java.gradle"
11 | }
12 |
13 | java {
14 | sourceCompatibility = JavaVersion.VERSION_1_8
15 | targetCompatibility = JavaVersion.VERSION_1_8
16 | withSourcesJar()
17 | withJavadocJar()
18 | }
19 |
20 | dependencies {
21 | implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.10"
22 | }
--------------------------------------------------------------------------------
/blink-annotation/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=blink-annotation
2 | POM_NAME=blink-annotation
3 | POM_DESCRIPTION=Blink navigator
--------------------------------------------------------------------------------
/blink-annotation/src/main/java/com/seewo/blink/annotation/BlinkMetadata.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 没有任何实际作用,仅为了方便标注Uri
10 | */
11 | @Retention(RetentionPolicy.SOURCE)
12 | @Target(ElementType.TYPE)
13 | public @interface BlinkMetadata {
14 | String[] value();
15 | }
16 |
--------------------------------------------------------------------------------
/blink-annotation/src/main/java/com/seewo/blink/annotation/BlinkUri.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 没有任何实际作用,仅为了方便标注Uri
10 | */
11 | @Retention(RetentionPolicy.SOURCE)
12 | @Target(ElementType.TYPE)
13 | public @interface BlinkUri {
14 | String[] value();
15 | }
16 |
--------------------------------------------------------------------------------
/blink-annotation/src/main/java/com/seewo/blink/annotation/metadata/BaseMetadata.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.annotation.metadata
2 |
3 | abstract class BaseMetadata {
4 | fun inject() {
5 | val ktx = Class.forName("com.seewo.blink.Initializer_${this::class.java.canonicalName.replace('.', '_')}Kt")
6 | ktx.getMethod("_inject", this::class.java).invoke(ktx, this)
7 | }
8 | }
--------------------------------------------------------------------------------
/blink-fragment/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/blink-fragment/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | if (LOCAL_DEBUG.toBoolean()) {
7 | apply from: "${project.rootDir}/gradle/local-maven-push.gradle"
8 | } else {
9 | apply from: "${project.rootDir}/gradle/jitpack-push.gradle"
10 | // apply from: "${project.rootDir}/gradle/jfrog-push.gradle"
11 | }
12 |
13 | android {
14 | namespace 'com.seewo.blink.fragment'
15 | compileSdk 33
16 |
17 | defaultConfig {
18 | minSdk 21
19 | targetSdk 28
20 |
21 | consumerProguardFiles "consumer-rules.pro"
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = '1.8'
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation 'androidx.appcompat:appcompat:1.6.1'
41 | implementation "androidx.startup:startup-runtime:1.1.1"
42 | implementation 'androidx.core:core-ktx:1.7.0'
43 | implementation 'androidx.fragment:fragment-ktx:1.5.7'
44 | api project(":blink-utils")
45 | api project(":blink-annotation")
46 | }
--------------------------------------------------------------------------------
/blink-fragment/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/blink-fragment/consumer-rules.pro
--------------------------------------------------------------------------------
/blink-fragment/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=blink-fragment
2 | POM_NAME=blink-fragment
3 | POM_DESCRIPTION=Blink navigator
--------------------------------------------------------------------------------
/blink-fragment/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/blink-fragment/src/androidTest/java/com/seewo/blink/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.seewo.blink.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/Blink.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment
2 |
3 | import android.net.Uri
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import com.seewo.blink.fragment.container.BlinkContainerFragment
7 | import com.seewo.blink.fragment.interceptor.BaseInterceptor
8 | import com.seewo.blink.fragment.interceptor.Interceptors
9 | import java.util.UUID
10 |
11 | object Blink {
12 | private const val REQUEST_TAG = "BLINK#REQUEST#TAG"
13 | internal var onNavigation: ((fragment: Fragment) -> Unit)? = null
14 | private val interceptors = Interceptors()
15 |
16 | private val onResults = mutableMapOf Unit>()
17 |
18 | /**
19 | * 添加拦截器
20 | */
21 | @JvmStatic
22 | fun add(interceptor: BaseInterceptor) {
23 | interceptors.add(interceptor)
24 | }
25 |
26 | /**
27 | * 移除拦截器
28 | */
29 | @JvmStatic
30 | fun remove(interceptor: BaseInterceptor) {
31 | interceptors.remove(interceptor)
32 | }
33 |
34 | suspend fun navigation(
35 | uri: Uri,
36 | from: Fragment? = null,
37 | onResult: ((Bundle?) -> Unit)? = null
38 | ) {
39 | from.doNavigation(uri, onResult)
40 | }
41 |
42 | private suspend fun Fragment?.doNavigation(
43 | uri: Uri,
44 | onResult: ((Bundle?) -> Unit)? = null
45 | ) {
46 | val to = Bundle().apply {
47 | setUri(uri)
48 | }
49 | interceptors.process(this@doNavigation, to)
50 | onNavigation?.invoke(BlinkContainerFragment().apply {
51 | attach(RouteMap.get(to.uriNonNull).apply {
52 | val requestTag =
53 | this@doNavigation?.generateFragmentTag ?: UUID.randomUUID().toString()
54 | onResult?.let {
55 | onResults[requestTag] = onResult
56 | }
57 | arguments = to.apply {
58 | putString(REQUEST_TAG, requestTag)
59 | }
60 | })
61 | })
62 | }
63 |
64 | fun returnResult(fragment: Fragment, result: Bundle?) {
65 | fragment.arguments?.getString(REQUEST_TAG)?.let {
66 | onResults.remove(it)?.invoke(result)
67 | }
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/BlinkFragmentKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.seewo.blink.fragment.container.BlinkContainerFragment
5 | import com.seewo.blink.fragment.mode.LaunchMode
6 | import com.seewo.blink.fragment.mode.SingleTaskFragment
7 | import com.seewo.blink.fragment.mode.SingleTopFragment
8 |
9 | private val Fragment.mode: LaunchMode
10 | get() = when (this) {
11 | is SingleTaskFragment -> LaunchMode.SINGLE_TASK
12 | is SingleTopFragment -> LaunchMode.SINGLE_TOP
13 | else -> LaunchMode.NORMAL
14 | }
15 |
16 | private val Fragment.who: String?
17 | get() = runCatching { Fragment::class.java.getDeclaredField("mWho").apply {
18 | isAccessible = true
19 | }.get(this) as? String }.getOrNull()
20 |
21 | val Fragment.generateFragmentTag: String
22 | get() = (this as? BlinkContainerFragment)?.fragmentTag
23 | ?: "$mode;${this.arguments?.uriOrNull ?: ""};${this::class.java.canonicalName};${hashCode()};${who}"
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/BlinkInitializer.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | class BlinkInitializer : Initializer{
7 | override fun create(context: Context) {
8 | // Blink.context = context
9 | }
10 |
11 | override fun dependencies(): MutableList>> = mutableListOf()
12 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/BlinkKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment
2 |
3 | import android.net.Uri
4 | import android.os.Bundle
5 | import androidx.core.net.toUri
6 | import androidx.fragment.app.Fragment
7 | import com.seewo.blink.fragment.container.BlinkContainerFragment
8 | import com.seewo.blink.fragment.interceptor.BaseInterceptor
9 | import com.seewo.blink.fragment.interceptor.InterruptedException
10 | import kotlinx.coroutines.MainScope
11 | import kotlinx.coroutines.launch
12 | import kotlinx.coroutines.runBlocking
13 |
14 | /**
15 | * 导航到指定Fragment
16 | *
17 | * @param uri 字符串类型的Uri
18 | * @param onResult 返回回调。
19 | *
20 | * @return 执行结果,可能存在以下两种异常
21 | * - FragmentNotFoundException 无法找到uri对应的Fragment
22 | * - 自定义异常 路由被拦截
23 | */
24 | @Deprecated("use Fragment.blinking() instead")
25 | fun Fragment.blink(
26 | uri: String,
27 | onResult: ((Bundle?) -> Unit)? = null
28 | ): Result = blink(uri.toUri(), onResult)
29 |
30 | /**
31 | * 导航到指定Fragment
32 | *
33 | * @param uri 字符串类型的Uri
34 | * @param onResult 返回回调。
35 | *
36 | * @return 执行结果,可能存在以下两种异常
37 | * - FragmentNotFoundException 无法找到uri对应的Fragment
38 | * - 自定义异常 路由被拦截
39 | */
40 | @Deprecated("use fragmentBlinking() instead")
41 | fun fragmentBlink(
42 | uri: String,
43 | onResult: ((Bundle?) -> Unit)? = null
44 | ): Result = fragmentBlink(uri.toUri(), onResult)
45 |
46 | /**
47 | * 导航到指定Fragment
48 | *
49 | * @param uri Uri
50 | * @param onResult 返回回调。
51 | *
52 | * @return 执行结果,可能存在以下两种异常
53 | * - FragmentNotFoundException 无法找到uri对应的Fragment
54 | * - 自定义异常 路由被拦截
55 | */
56 | @Deprecated("use Fragment.blinking() instead")
57 | fun Fragment.blink(
58 | uri: Uri,
59 | onResult: ((Bundle?) -> Unit)? = null
60 | ): Result = runCatching { runBlocking {
61 | Blink.navigation(uri, this@blink, onResult)
62 | } }
63 |
64 | /**
65 | * 导航到指定Fragment
66 | *
67 | * @param uri Uri
68 | * @param onResult 返回回调。
69 | *
70 | * @return 执行结果,可能存在以下两种异常
71 | * - FragmentNotFoundException 无法找到uri对应的Fragment
72 | * - 自定义异常 路由被拦截
73 | */
74 | @Deprecated("use fragmentBlinking() instead")
75 | fun fragmentBlink(
76 | uri: Uri,
77 | onResult: ((Bundle?) -> Unit)? = null
78 | ): Result = runCatching { runBlocking {
79 | Blink.navigation(uri, null, onResult)
80 | } }
81 |
82 | /**
83 | * 导航到指定Fragment
84 | *
85 | * @param uri 字符串类型的Uri
86 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
87 | * @param onResult 返回回调。
88 | *
89 | * @return 执行结果,可能存在以下两种异常
90 | * - FragmentNotFoundException 无法找到uri对应的Fragment
91 | * - 自定义异常 路由被拦截
92 | */
93 | fun Fragment.blinking(
94 | uri: String,
95 | onIntercepted: ((Throwable?) -> Unit)? = null,
96 | onResult: ((Bundle?) -> Unit)? = null
97 | ) = blinking(uri.toUri(), onIntercepted, onResult)
98 |
99 | /**
100 | * 导航到指定Fragment
101 | *
102 | * @param uri 字符串类型的Uri
103 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
104 | * @param onResult 返回回调。
105 | *
106 | * @return 执行结果,可能存在以下两种异常
107 | * - FragmentNotFoundException 无法找到uri对应的Fragment
108 | * - 自定义异常 路由被拦截
109 | */
110 | fun fragmentBlinking(
111 | uri: String,
112 | onIntercepted: ((Throwable?) -> Unit)? = null,
113 | onResult: ((Bundle?) -> Unit)? = null
114 | ) = fragmentBlinking(uri.toUri(), onIntercepted, onResult)
115 |
116 | /**
117 | * 异步执行,导航到指定Fragment
118 | *
119 | * @param uri Uri
120 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
121 | * @param onResult 返回回调。
122 | *
123 | * @return 执行结果,可能存在以下两种异常
124 | * - FragmentNotFoundException 无法找到uri对应的Fragment
125 | * - 自定义异常 路由被拦截
126 | */
127 | fun Fragment.blinking(
128 | uri: Uri,
129 | onIntercepted: ((Throwable?) -> Unit)? = null,
130 | onResult: ((Bundle?) -> Unit)? = null
131 | ) {
132 | MainScope().launch {
133 | runCatching { Blink.navigation(uri, this@blinking, onResult) }.apply {
134 | onIntercepted?.invoke(exceptionOrNull())
135 | }
136 | }
137 | }
138 |
139 | /**
140 | * 异步执行,导航到指定Fragment
141 | *
142 | * @param uri Uri
143 | * @param onIntercepted 路由被拦截回调。如果回调返回的Throwable为null则表示路由成功执行
144 | * @param onResult 返回回调。
145 | *
146 | * @return 执行结果,可能存在以下两种异常
147 | * - FragmentNotFoundException 无法找到uri对应的Fragment
148 | * - 自定义异常 路由被拦截
149 | */
150 | fun fragmentBlinking(
151 | uri: Uri,
152 | onIntercepted: ((Throwable?) -> Unit)? = null,
153 | onResult: ((Bundle?) -> Unit)? = null
154 | ) {
155 | MainScope().launch {
156 | runCatching { Blink.navigation(uri, null, onResult) }.apply {
157 | onIntercepted?.invoke(exceptionOrNull())
158 | }
159 | }
160 | }
161 |
162 | /**
163 | * 返回,相当于Activity的finish,但可以返回数据给路由发起者
164 | */
165 | fun Fragment.pop(result: Bundle? = null) {
166 | (parentFragment as? BlinkContainerFragment)?.popResult(result) ?: parentFragmentManager.popBackStack()
167 | }
168 |
169 | /**
170 | * 返回到指定的Fragment(用uri来指定)
171 | *
172 | * @param uri 回退到的页面对应的uri。如果页面定义了多个uri,回退时只会匹配到实际导航到该页面的uri
173 | * @return 是否成功回退
174 | *
175 | * 特别注意:
176 | * 1. 如果回退栈中存在多个uri定义相同的Fragment,那会回退到最近的一个
177 | * 2. 需要回退到首个Fragment,即通过 BlinkContainerActivity.startFragment()传入的Fragment,其对应的uri为空字符串
178 | */
179 | fun Fragment.popTo(uri: String): Boolean {
180 | return (parentFragment as? BlinkContainerFragment)?.popTo(uri) ?: false
181 | }
182 |
183 | /**
184 | * 添加拦截器
185 | */
186 | fun BaseInterceptor.attach() {
187 | Blink.add(this)
188 | }
189 |
190 | /**
191 | * 移除拦截器
192 | */
193 | fun BaseInterceptor.detach() {
194 | Blink.remove(this)
195 | }
196 |
197 | /**
198 | * 拦截器拦截路由建议抛出以下异常
199 | */
200 | fun BaseInterceptor.interrupt(msg: String? = null) {
201 | throw InterruptedException(this, msg)
202 | }
203 |
204 | fun Fragment.stringParams(name: String): Lazy = lazy {
205 | arguments?.uriOrNull?.getQueryParameter(name)
206 | }
207 |
208 | fun Fragment.stringParamsNonNull(name: String): Lazy = lazy {
209 | arguments?.uriOrNull?.getQueryParameter(name) ?: ""
210 | }
211 |
212 | fun Fragment.stringsParams(name: String): Lazy?> = lazy {
213 | arguments?.uriOrNull?.getQueryParameters(name)
214 | }
215 |
216 | fun Fragment.stringsParamsNonNull(name: String): Lazy> = lazy {
217 | arguments?.uriOrNull?.getQueryParameters(name) ?: listOf()
218 | }
219 |
220 | fun Fragment.boolParams(name: String, default: Boolean = false): Lazy = lazy {
221 | arguments?.uriOrNull?.getBooleanQueryParameter(name, default) ?: default
222 | }
223 |
224 | fun Fragment.intParams(name: String, default: Int = 0): Lazy = lazy {
225 | arguments?.uriOrNull?.getQueryParameter(name)?.toIntOrNull() ?: default
226 | }
227 |
228 | fun Fragment.longParams(name: String, default: Long = 0L): Lazy = lazy {
229 | arguments?.uriOrNull?.getQueryParameter(name)?.toLongOrNull() ?: default
230 | }
231 |
232 | fun Fragment.floatParams(name: String, default: Float = 0f): Lazy = lazy {
233 | arguments?.uriOrNull?.getQueryParameter(name)?.toFloatOrNull() ?: default
234 | }
235 |
236 | fun Fragment.doubleParams(name: String, default: Double = 0.0): Lazy = lazy {
237 | arguments?.uriOrNull?.getQueryParameter(name)?.toDoubleOrNull() ?: default
238 | }
239 |
240 | inline fun Fragment.enumParams(name: String): Lazy = lazy {
241 | if (T::class.java.isEnum) {
242 | val value = arguments?.uriOrNull?.getQueryParameter(name)
243 | val valueInt = value?.toIntOrNull()
244 | if (valueInt != null) {
245 | T::class.java.runCatching { enumConstants!![valueInt] }.getOrNull()
246 | } else if (value != null){
247 | T::class.java.runCatching { getMethod("valueOf", String::class.java).invoke(null, value) }.getOrNull() as T?
248 | } else null
249 | } else null
250 | }
251 |
252 | val Bundle.uriNonNull: Uri
253 | get() = uriOrNull!!
254 |
255 | val Bundle.uriOrNull: Uri?
256 | get() = getParcelable(RouteMap.KEY_URI)
257 |
258 | fun Bundle.setUri(uri: String) {
259 | setUri(uri.toUri())
260 | }
261 |
262 | fun Bundle.setUri(uri: Uri) {
263 | putParcelable(RouteMap.KEY_URI, uri)
264 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/RouteMap.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment
2 |
3 | import android.net.Uri
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import com.seewo.blink.fragment.container.NullFragment
7 | import com.seewo.blink.utils.baseUri
8 | import java.util.concurrent.ConcurrentHashMap
9 |
10 | /**
11 | * 路由表,可手动注册,也可通过ksp动态注册
12 | */
13 | object RouteMap {
14 | const val KEY_URI = "uri"
15 | private val routeMetadataMap = ConcurrentHashMap>()
16 |
17 | fun register(baseUri: String, fragment: Class) {
18 | val confirmedBaseUri = baseUri.baseUri
19 | routeMetadataMap[confirmedBaseUri] = fragment
20 | }
21 |
22 | fun get(uri: String): Fragment = get(Uri.parse(uri))
23 |
24 | fun get(uri: Uri): Fragment = (routeMetadataMap[uri.baseUri]?.newInstance() ?: NullFragment()).apply {
25 | arguments = (arguments ?: Bundle()).apply {
26 | putParcelable(KEY_URI, uri)
27 | }
28 | }
29 | }
30 |
31 | private val String.baseUri: String
32 | get() = split("?").first()
33 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/Background.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation;
2 |
3 | import androidx.annotation.ColorInt;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * 定义页面背景颜色,未设置则取窗口背景颜色,取不到则为白色
12 | */
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Target(ElementType.TYPE)
15 | public @interface Background {
16 | @ColorInt int value();
17 | }
18 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/CustomAnimations.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation
2 |
3 | import androidx.annotation.AnimRes
4 | import androidx.annotation.AnimatorRes
5 |
6 | @Retention(AnnotationRetention.RUNTIME)
7 | @Target(AnnotationTarget.CLASS)
8 | annotation class CustomAnimations(
9 | @AnimatorRes @AnimRes val enter: Int = 0,
10 | @AnimatorRes @AnimRes val exit: Int = 0,
11 | @AnimatorRes @AnimRes val popEnter: Int = 0,
12 | @AnimatorRes @AnimRes val popExit: Int = 0,
13 | )
14 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/KeepAlive.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 定义页面处于非栈顶时是否保活,不保活的,返回栈顶时会重建并无法保持状态
10 | *
11 | * 对于未使用KeepAlive注解去定义的Fragment,默认为非保活
12 | */
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Target(ElementType.TYPE)
15 | public @interface KeepAlive {
16 | boolean value() default true;
17 | }
18 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/Orientation.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 默认页面方向(参考以下常量设置)
10 | *
11 | * @see android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE
12 | * @see android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT
13 | * @see android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED
14 | */
15 | @Retention(RetentionPolicy.RUNTIME)
16 | @Target(ElementType.TYPE)
17 | public @interface Orientation {
18 | int value();
19 | }
20 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/SystemUI.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation
2 |
3 | /**
4 | * 系统UI的默认样式
5 | *
6 | * @param hideStatusBar true 隐藏状态栏
7 | * @param hideNavigationBar true 隐藏导航栏
8 | * @param brightnessLight true 系统状态栏、导航栏为白底黑字; false 系统状态栏为黑底白字
9 | */
10 | @Retention(AnnotationRetention.RUNTIME)
11 | @Target(AnnotationTarget.CLASS)
12 | annotation class SystemUI(
13 | val hideStatusBar: Boolean = false,
14 | val hideNavigationBar: Boolean = false,
15 | val brightnessLight: Boolean = true,
16 | )
17 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/bean/CustomAnimationSettings.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation.bean
2 |
3 | import androidx.annotation.AnimRes
4 | import androidx.annotation.AnimatorRes
5 |
6 | internal class CustomAnimationSettings(
7 | @AnimatorRes @AnimRes val enter: Int = 0,
8 | @AnimatorRes @AnimRes val exit: Int = 0,
9 | @AnimatorRes @AnimRes val popEnter: Int = 0,
10 | @AnimatorRes @AnimRes val popExit: Int = 0,
11 | )
12 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/annotation/bean/SystemUiSettings.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.annotation.bean
2 |
3 | /**
4 | * 系统UI的默认样式
5 | *
6 | * @param fullscreen true 全屏; false 非全屏
7 | * @param statusBarLight true 系统状态栏为黑色字体; false 系统状态栏为白色字体
8 | * @param navigationBarLight true 导航栏为白色; false 导航栏为深色
9 | */
10 | internal class SystemUiSettings(
11 | val fullscreen: Boolean = false,
12 | val statusBarLight: Boolean = true,
13 | val navigationBarLight: Boolean = true,
14 | )
15 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/container/BlinkContainerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.container
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import androidx.fragment.app.FragmentActivity
6 | import androidx.fragment.app.FragmentManager
7 | import androidx.fragment.app.FragmentManager.BackStackEntry
8 | import androidx.fragment.app.FragmentTransaction
9 | import androidx.fragment.app.commit
10 | import com.seewo.blink.fragment.Blink
11 | import com.seewo.blink.fragment.R
12 | import com.seewo.blink.fragment.generateFragmentTag
13 | import com.seewo.blink.fragment.mode.LaunchMode.NORMAL
14 | import com.seewo.blink.fragment.mode.LaunchMode.SINGLE_TASK
15 | import com.seewo.blink.fragment.mode.LaunchMode.SINGLE_TOP
16 | import com.seewo.blink.fragment.mode.ReEnterFragment
17 |
18 | abstract class BlinkContainerActivity : FragmentActivity() {
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | setContentView(R.layout.blink_fragment_activity)
23 | Blink.onNavigation = this::load
24 | if (savedInstanceState != null) return
25 | startFragment()?.let {
26 | supportFragmentManager.commit {
27 | add(R.id.blink_container_activity_root, BlinkContainerFragment().apply {
28 | attach(it)
29 | })
30 | }
31 | }
32 | }
33 |
34 | /**
35 | * 设置入口Fragment,若为null则不设置入口Fragment,后续Fragment通过路由跳转
36 | */
37 | protected abstract fun startFragment(): Fragment?
38 |
39 | override fun onDestroy() {
40 | super.onDestroy()
41 | Blink.onNavigation = null
42 | }
43 |
44 | private fun FragmentManager.findBackStackEntry(block: (BackStackEntry) -> Boolean): BackStackEntry? {
45 | for (i in 0 until backStackEntryCount) {
46 | val entry = getBackStackEntryAt(i)
47 | if (block(entry)) {
48 | return entry
49 | }
50 | }
51 | return null
52 | }
53 |
54 | private fun load(fragment: Fragment) {
55 | supportFragmentManager.commit {
56 | val customAnimation = (fragment as? BlinkContainerFragment)?.customAnimation
57 | if (customAnimation == null) {
58 | setCustomAnimations(
59 | R.anim.enter_from_right, R.anim.fade_out,
60 | R.anim.fade_in, R.anim.exit_to_right
61 | )
62 | } else {
63 | setCustomAnimations(
64 | customAnimation.enter, customAnimation.exit,
65 | customAnimation.popEnter, customAnimation.popExit)
66 | }
67 | val fragmentTag = FragmentTag((fragment as? BlinkContainerFragment)?.fragmentTag
68 | ?: fragment.generateFragmentTag)
69 | when (fragmentTag.launchMode) {
70 | NORMAL -> launchFragment(fragment)
71 | SINGLE_TOP -> handleSingleTop(fragment)
72 | SINGLE_TASK -> handleSingleTask(fragment)
73 | }
74 | }
75 | }
76 |
77 | private fun FragmentTransaction.handleSingleTask(fragment: Fragment) {
78 | val oldFragmentEntry =
79 | supportFragmentManager.findBackStackEntry {
80 | val realFragment = (fragment as? BlinkContainerFragment)?.fragment
81 | ?: fragment
82 | FragmentTag(it.name).className == realFragment::class.java.canonicalName
83 | }
84 | if (oldFragmentEntry != null) {
85 | supportFragmentManager.popBackStackImmediate(oldFragmentEntry.name, 1)
86 | val reEnteringFragment =
87 | supportFragmentManager.findFragmentById(R.id.blink_container_activity_root)
88 | (reEnteringFragment as? BlinkContainerFragment)?.onNewArguments(
89 | fragment.arguments
90 | ) ?: (reEnteringFragment as? ReEnterFragment)?.onNewArguments(fragment.arguments)
91 | } else {
92 | launchFragment(fragment)
93 | }
94 | }
95 |
96 | private fun FragmentTransaction.handleSingleTop(fragment: Fragment) {
97 | val currentFragment =
98 | (currentFragment as? BlinkContainerFragment)?.fragment ?: currentFragment
99 | if (currentFragment != null) {
100 | val lastBackStackEntry =
101 | FragmentTag((currentFragment as? BlinkContainerFragment)?.fragmentTag ?: currentFragment.generateFragmentTag)
102 | val currentBackStackEntry = FragmentTag((fragment as? BlinkContainerFragment)?.fragmentTag ?: fragment.generateFragmentTag)
103 | if (lastBackStackEntry.className == currentBackStackEntry.className) {
104 | (this@BlinkContainerActivity.currentFragment as? BlinkContainerFragment)?.onNewArguments(fragment.arguments)
105 | } else {
106 | launchFragment(fragment)
107 | }
108 | } else {
109 | launchFragment(fragment)
110 | }
111 | }
112 |
113 | private fun FragmentTransaction.launchFragment(fragment: Fragment) {
114 | currentFragment?.let {
115 | val keepAlive = (fragment as? BlinkContainerFragment)?.keepAlive
116 | if (keepAlive?.value != true) {
117 | remove(it)
118 | } else {
119 | hide(it)
120 | }
121 | if (it is BlinkContainerFragment) {
122 | addToBackStack(it.fragmentTag)
123 | } else {
124 | addToBackStack(it.generateFragmentTag)
125 | }
126 | }
127 | add(R.id.blink_container_activity_root, fragment, fragment::class.java.canonicalName)
128 | }
129 |
130 | private val currentFragment: Fragment?
131 | get() = supportFragmentManager.findFragmentById(R.id.blink_container_activity_root)
132 |
133 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/container/BlinkContainerFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.container
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.graphics.Color
6 | import android.os.Bundle
7 | import android.util.TypedValue
8 | import android.view.LayoutInflater
9 | import android.view.ViewGroup
10 | import androidx.fragment.app.Fragment
11 | import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE
12 | import androidx.fragment.app.commit
13 | import com.seewo.blink.fragment.Blink
14 | import com.seewo.blink.fragment.R
15 | import com.seewo.blink.fragment.annotation.Background
16 | import com.seewo.blink.fragment.annotation.CustomAnimations
17 | import com.seewo.blink.fragment.annotation.KeepAlive
18 | import com.seewo.blink.fragment.annotation.Orientation
19 | import com.seewo.blink.fragment.annotation.SystemUI
20 | import com.seewo.blink.fragment.exception.FragmentNotFoundException
21 | import com.seewo.blink.fragment.generateFragmentTag
22 | import com.seewo.blink.fragment.mode.ReEnterFragment
23 | import com.seewo.blink.fragment.utils.hideNavigationBar
24 | import com.seewo.blink.fragment.utils.hideStatusBar
25 | import com.seewo.blink.fragment.utils.setStatusBarTransparent
26 | import com.seewo.blink.fragment.utils.showNavigationBar
27 | import com.seewo.blink.fragment.utils.showStatusBar
28 |
29 |
30 | @SuppressLint("SourceLockedOrientationActivity")
31 | internal class BlinkContainerFragment : Fragment() {
32 | lateinit var fragmentTag: String
33 | private var orientation: Int? = null
34 | private var systemUISettings: SystemUI = SystemUI()
35 | private var backgroundColor: Int? = null
36 | var customAnimation: CustomAnimations? = null
37 | private set
38 |
39 | var keepAlive: KeepAlive? = null
40 | private set
41 |
42 | override fun onCreateView(
43 | inflater: LayoutInflater,
44 | container: ViewGroup?,
45 | savedInstanceState: Bundle?
46 | ) = inflater.inflate(R.layout.blink_container_fragment, container, false).apply {
47 | setBackgroundColor(backgroundColor
48 | ?: kotlin.runCatching { windowBackground }.getOrNull()
49 | ?: Color.WHITE)
50 | }!!
51 |
52 | private var pending: Runnable? = null
53 | private var result: Bundle? = null
54 |
55 | var fragment: Fragment? = null
56 |
57 | fun popResult(result: Bundle? = null) {
58 | this.result = result
59 | parentFragmentManager.popBackStack()
60 | }
61 |
62 | fun popTo(uri: String): Boolean {
63 | for (i in parentFragmentManager.backStackEntryCount - 1 downTo 0) {
64 | val name = parentFragmentManager.getBackStackEntryAt(i).name
65 | val tag = FragmentTag(name)
66 | if (tag.uri == uri) {
67 | parentFragmentManager.popBackStack(name, POP_BACK_STACK_INCLUSIVE)
68 | return true
69 | }
70 | }
71 | return false
72 | }
73 |
74 | override fun onAttach(context: Context) {
75 | super.onAttach(context)
76 | pending?.run()
77 | pending = null
78 | mayUpdateFragmentSettings()
79 | }
80 |
81 | private fun mayUpdateFragmentSettings() {
82 | if (isAdded && !isHidden && userVisibleHint && isResumed) {
83 | orientation?.let { requireActivity().requestedOrientation = it }
84 | systemUISettings.run {
85 | requireActivity().setStatusBarTransparent(brightnessLight)
86 | if (hideStatusBar) {
87 | requireActivity().hideStatusBar()
88 | } else {
89 | requireActivity().showStatusBar()
90 | }
91 | if (hideNavigationBar) {
92 | requireActivity().hideNavigationBar()
93 | } else {
94 | requireActivity().showNavigationBar()
95 | }
96 | }
97 | }
98 | }
99 |
100 | override fun onDestroy() {
101 | super.onDestroy()
102 | fragment?.let {
103 | Blink.returnResult(it, result)
104 | }
105 | }
106 |
107 | internal fun attach(fragment: Fragment) {
108 | fragment.checkException()
109 | this.fragment = fragment
110 | arguments = fragment.arguments
111 | fragmentTag = fragment.generateFragmentTag
112 | fragment::class.java.apply {
113 | getAnnotation(Orientation::class.java)?.let {
114 | orientation = it.value
115 | }
116 | getAnnotation(SystemUI::class.java)?.let { systemUISettings = it }
117 | getAnnotation(Background::class.java)?.let { backgroundColor = it.value }
118 | customAnimation = getAnnotation(CustomAnimations::class.java)
119 | keepAlive = getAnnotation(KeepAlive::class.java)
120 | }
121 | if (isAdded) {
122 | doAttach(fragment)
123 | } else {
124 | pending = Runnable {
125 | doAttach(fragment)
126 | }
127 | }
128 | }
129 |
130 | private fun doAttach(fragment: Fragment) {
131 | childFragmentManager.commit {
132 | add(R.id.blink_container_fragment_root, fragment)
133 | }
134 | }
135 |
136 | private fun Fragment.checkException() {
137 | if (this is NullFragment) throw FragmentNotFoundException(this)
138 | }
139 |
140 | override fun onHiddenChanged(hidden: Boolean) {
141 | super.onHiddenChanged(hidden)
142 | mayUpdateFragmentSettings()
143 | }
144 |
145 | override fun onResume() {
146 | super.onResume()
147 | mayUpdateFragmentSettings()
148 | }
149 |
150 | fun onNewArguments(newArguments: Bundle?) {
151 | when (val currentFragment =
152 | childFragmentManager.findFragmentById(R.id.blink_container_fragment_root)) {
153 | is ReEnterFragment -> currentFragment.onNewArguments(newArguments)
154 | }
155 | }
156 |
157 | private val windowBackground: Int
158 | get() {
159 | val typedValue = TypedValue()
160 | requireContext().theme.resolveAttribute(
161 | android.R.attr.windowBackground,
162 | typedValue,
163 | true
164 | )
165 | val colorRes = typedValue.resourceId
166 | return requireContext().resources.getColor(colorRes)
167 | }
168 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/container/FragmentTag.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.container
2 |
3 | import com.seewo.blink.fragment.mode.LaunchMode
4 |
5 | internal class FragmentTag(private val tag: String?) {
6 | val launchMode: LaunchMode
7 | val uri: String?
8 | val className: String?
9 | val hashCode: Int
10 |
11 | init {
12 | val tags = tag?.split(";")
13 | launchMode = kotlin.runCatching {
14 | tags?.get(0)?.let { LaunchMode.valueOf(it) }
15 | }.getOrNull() ?: LaunchMode.NORMAL
16 | uri = kotlin.runCatching { tags?.get(1) }.getOrNull()
17 | className = kotlin.runCatching { tags?.get(2) }.getOrNull()
18 | hashCode = kotlin.runCatching { tags?.get(3) }.getOrNull()?.toIntOrNull() ?: 0
19 | }
20 |
21 | override fun toString(): String = tag ?: super.toString()
22 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/container/NullFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.container
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | class NullFragment: Fragment()
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/exception/FragmentNotFoundException.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.exception
2 |
3 | import android.net.Uri
4 | import com.seewo.blink.fragment.RouteMap
5 | import com.seewo.blink.fragment.container.NullFragment
6 | import com.seewo.blink.fragment.uriOrNull
7 |
8 | class FragmentNotFoundException(fragment: NullFragment) : RuntimeException(
9 | "Cannot find fragment with uri: ${
10 | fragment.arguments?.getParcelable(
11 | RouteMap.KEY_URI
12 | )
13 | }"
14 | ) {
15 | val uri = fragment.arguments?.uriOrNull
16 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/interceptor/AsyncInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.interceptor
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 |
6 | interface AsyncInterceptor: BaseInterceptor {
7 |
8 | /**
9 | * 拦截器处理函数,如果需要拦截路由,可以抛异常,异常可以自定义
10 | *
11 | * @param from 路由来源,如果不是从Fragment发起则为空
12 | * @param target 路由目标arguments,最终会从中取出uri,并索引到Fragment
13 | * @return 最终路由目标。如果希望通过uri来索引目标Fragment,可以通过RouteMetadata来索引
14 | * @throws InterruptedException 建议拦截路由抛这个异常
15 | */
16 | @kotlin.jvm.Throws(InterruptedException::class)
17 | suspend fun process(from: Fragment?, target: Bundle)
18 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/interceptor/BaseInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.interceptor
2 |
3 | import android.os.Bundle
4 |
5 | interface BaseInterceptor {
6 | /**
7 | * 过滤器
8 | * @return 仅在函数返回true时,过滤器生效。默认不过滤。
9 | */
10 | fun filter(target: Bundle): Boolean = true
11 | /**
12 | * 优先级:数字大的优先级高,允许负数
13 | */
14 | fun priority(): Int = 0
15 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/interceptor/Interceptor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.interceptor
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 |
6 | @Deprecated("use AsyncInterceptor instead")
7 | interface Interceptor: BaseInterceptor {
8 |
9 | /**
10 | * 拦截器处理函数,如果需要拦截路由,可以抛异常,异常可以自定义
11 | *
12 | * @param from 路由来源,如果不是从Fragment发起则为空
13 | * @param target 路由目标arguments,最终会从中取出uri,并索引到Fragment
14 | * @return 最终路由目标。如果希望通过uri来索引目标Fragment,可以通过RouteMetadata来索引
15 | * @throws InterruptedException 建议拦截路由抛这个异常
16 | */
17 | @kotlin.jvm.Throws(InterruptedException::class)
18 | fun process(from: Fragment?, target: Bundle)
19 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/interceptor/Interceptors.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.interceptor
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 |
6 | private const val GREEN_CHANNEL = "BLINK#GREEN#CHANNEL"
7 |
8 | internal class Interceptors {
9 | private val interceptors = mutableListOf()
10 |
11 | @Synchronized
12 | fun add(interceptor: BaseInterceptor) {
13 | if (interceptors.contains(interceptor)) return
14 | interceptors += interceptor
15 | interceptors.sortByDescending { it.priority() }
16 | }
17 |
18 | @Synchronized
19 | fun remove(interceptor: BaseInterceptor) {
20 | interceptors.remove(interceptor)
21 | }
22 |
23 | suspend fun process(from: Fragment?, target: Bundle) {
24 | interceptors.filter {
25 | it.filter(target) && !target.isInGreenChannel(it)
26 | }.forEach {
27 | if (it is Interceptor) {
28 | it.process(from, target)
29 | } else if (it is AsyncInterceptor) {
30 | it.process(from, target)
31 | }
32 | }
33 | }
34 |
35 | private fun Bundle.isInGreenChannel(interceptor: BaseInterceptor): Boolean =
36 | getSerializable(GREEN_CHANNEL) == interceptor::class.java
37 | }
38 |
39 | fun BaseInterceptor.putInGreenChannel(target: Bundle) {
40 | target.putSerializable(GREEN_CHANNEL, this::class.java)
41 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/interceptor/InterruptedException.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.interceptor
2 |
3 | open class InterruptedException(
4 | val interceptor: BaseInterceptor, msg: String? = null
5 | ): RuntimeException("Interrupted By ${interceptor::class.java.simpleName} $msg")
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/mode/LaunchMode.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.mode
2 |
3 | enum class LaunchMode {
4 | NORMAL, SINGLE_TOP, SINGLE_TASK
5 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/mode/ReEnterFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.mode
2 |
3 | import android.os.Bundle
4 |
5 | interface ReEnterFragment {
6 | fun onNewArguments(arguments: Bundle?)
7 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/mode/SingleTaskFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.mode
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 |
6 | abstract class SingleTaskFragment : Fragment(), ReEnterFragment {
7 | override fun onNewArguments(arguments: Bundle?) = Unit
8 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/mode/SingleTopFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.mode
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 |
6 | abstract class SingleTopFragment : Fragment(), ReEnterFragment {
7 | override fun onNewArguments(arguments: Bundle?) = Unit
8 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/utils/SystemUiUtils.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.utils
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.graphics.Color
6 | import android.os.Build
7 | import android.view.WindowManager
8 | import androidx.core.view.WindowCompat
9 | import androidx.core.view.WindowInsetsCompat
10 | import androidx.core.view.WindowInsetsControllerCompat
11 |
12 | fun Activity.hideStatusBar() {
13 | WindowCompat.getInsetsController(window, window.decorView).run {
14 | hide(WindowInsetsCompat.Type.statusBars())
15 | WindowCompat.setDecorFitsSystemWindows(window, false)
16 | systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
17 | }
18 | }
19 |
20 | fun Activity.showStatusBar() {
21 | WindowCompat.getInsetsController(window, window.decorView).run {
22 | show(WindowInsetsCompat.Type.statusBars())
23 | }
24 | }
25 |
26 | fun Activity.hideNavigationBar() {
27 | WindowCompat.getInsetsController(window, window.decorView).run {
28 | hide(WindowInsetsCompat.Type.navigationBars())
29 | WindowCompat.setDecorFitsSystemWindows(window, false)
30 | systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
31 | }
32 | }
33 |
34 | fun Activity.showNavigationBar() {
35 | WindowCompat.getInsetsController(window, window.decorView).run {
36 | show(WindowInsetsCompat.Type.navigationBars())
37 | }
38 | }
39 |
40 | fun Activity.setStatusBarTransparent(brightnessLight: Boolean) {
41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
42 | window.attributes.layoutInDisplayCutoutMode =
43 | WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
44 | }
45 | setStatusBarTransparentOld(brightnessLight)
46 | }
47 |
48 | private fun Activity.setStatusBarTransparentOld(brightnessLight: Boolean) {
49 | when {
50 | MIUISetStatusBarLightMode(brightnessLight) -> Unit
51 | FlymeSetStatusBarLightMode(brightnessLight) -> Unit
52 | Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
53 | setStatusBarTransparentWithSys(brightnessLight)
54 | }
55 | }
56 | }
57 |
58 | /**
59 | * 设置状态栏图标为深色和魅族特定的文字风格,Flyme4.0以上
60 | * 可以用来判断是否为Flyme用户
61 | *
62 | * @param dark 是否把状态栏字体及图标颜色设置为深色
63 | * @return boolean 成功执行返回true
64 | */
65 | private fun Activity.FlymeSetStatusBarLightMode(dark: Boolean): Boolean {
66 | var result = false
67 | if (window != null) {
68 | try {
69 | val lp = window.attributes
70 | val darkFlag = WindowManager.LayoutParams::class.java
71 | .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON")
72 | val meizuFlags = WindowManager.LayoutParams::class.java
73 | .getDeclaredField("meizuFlags")
74 | darkFlag.isAccessible = true
75 | meizuFlags.isAccessible = true
76 | val bit = darkFlag.getInt(null)
77 | var value = meizuFlags.getInt(lp)
78 | value = if (dark) {
79 | value or bit
80 | } else {
81 | value and bit.inv()
82 | }
83 | meizuFlags.setInt(lp, value)
84 | window.attributes = lp
85 | result = true
86 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
87 | // 新版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
88 | setStatusBarTransparentWithSys(dark)
89 | }
90 | } catch (ignore: Exception) { }
91 | }
92 | return result
93 | }
94 |
95 | /**
96 | * 需要MIUIV6以上
97 | *
98 | * @param dark 是否把状态栏文字及图标颜色设置为深色
99 | * @return boolean 成功执行返回true
100 | */
101 | private fun Activity.MIUISetStatusBarLightMode(dark: Boolean): Boolean {
102 | var result = false
103 | if (window != null) {
104 | val clazz: Class<*> = window.javaClass
105 | try {
106 | var darkModeFlag = 0
107 | @SuppressLint("PrivateApi") val layoutParams =
108 | Class.forName("android.view.MiuiWindowManager\$LayoutParams")
109 | val field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE")
110 | darkModeFlag = field.getInt(layoutParams)
111 | val extraFlagField = clazz.getMethod(
112 | "setExtraFlags",
113 | Int::class.javaPrimitiveType,
114 | Int::class.javaPrimitiveType
115 | )
116 | if (dark) {
117 | extraFlagField.invoke(window, darkModeFlag, darkModeFlag) //状态栏透明且黑色字体
118 | } else {
119 | extraFlagField.invoke(window, 0, darkModeFlag) //清除黑色字体
120 | }
121 | result = true
122 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
123 | //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
124 | setStatusBarTransparentWithSys(dark)
125 | }
126 | } catch (ignore: Exception) { }
127 | }
128 | return result
129 | }
130 |
131 | private fun Activity.setStatusBarTransparentWithSys(lightStatusBar: Boolean) {
132 | WindowCompat.getInsetsController(window, window.decorView).run {
133 | isAppearanceLightStatusBars = lightStatusBar
134 | isAppearanceLightNavigationBars = lightStatusBar
135 | }
136 | window.run {
137 | addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
138 | statusBarColor = Color.TRANSPARENT
139 | navigationBarColor = Color.TRANSPARENT
140 | }
141 | WindowCompat.setDecorFitsSystemWindows(window, false)
142 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/java/com/seewo/blink/fragment/view/WindowInsetsFrameLayout.java:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.view.WindowInsets;
7 | import android.widget.FrameLayout;
8 |
9 | public class WindowInsetsFrameLayout extends FrameLayout {
10 |
11 | public WindowInsetsFrameLayout(Context context) {
12 | this(context, null);
13 | }
14 |
15 | public WindowInsetsFrameLayout(Context context, AttributeSet attrs) {
16 | this(context, attrs, 0);
17 | }
18 |
19 | public WindowInsetsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
20 | super(context,attrs,defStyleAttr);
21 | setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
22 | @Override
23 | public void onChildViewAdded(View parent, View child) {
24 | requestApplyInsets();
25 | }
26 |
27 | @Override
28 | public void onChildViewRemoved(View parent, View child) {
29 |
30 | }
31 | });
32 | }
33 |
34 | @Override
35 | public WindowInsets onApplyWindowInsets(WindowInsets insets) {
36 | int childCount = getChildCount();
37 | for (int index = 0; index < childCount; index++) {
38 | getChildAt(index).dispatchApplyWindowInsets(insets);
39 | }
40 | return insets;
41 | }
42 |
43 | @Override
44 | public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
45 | //重写分发方法,不判断是否消费
46 | for (int index = 0; index < getChildCount(); index++) {
47 | try {
48 | getChildAt(index).dispatchApplyWindowInsets(insets);
49 | } catch (Throwable e) {
50 | e.printStackTrace();
51 | }
52 | }
53 | return insets;
54 | }
55 | }
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/empty_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/enter_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/enter_from_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/enter_from_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/enter_from_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/exit_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/exit_to_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/exit_to_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/exit_to_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/layout/blink_container_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/layout/blink_fragment_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/blink-fragment/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/blink-fragment/src/test/java/com/seewo/blink/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/blink-ksp/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/blink-ksp/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'org.jetbrains.kotlin.jvm'
4 | }
5 | if (LOCAL_DEBUG.toBoolean()) {
6 | apply from: "${project.rootDir}/gradle/local-maven-push.gradle"
7 | } else {
8 | apply from: "${project.rootDir}/gradle/jitpack-push-java.gradle"
9 | // apply from: "${project.rootDir}/gradle/jfrog-push-java.gradle"
10 | }
11 | dependencies {
12 | implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.10"
13 | implementation "com.google.devtools.ksp:symbol-processing-api:1.6.21-1.0.6"
14 | implementation("com.squareup:kotlinpoet:1.9.0")
15 | implementation project(":blink-annotation")
16 | }
17 | java {
18 | sourceCompatibility = JavaVersion.VERSION_1_8
19 | targetCompatibility = JavaVersion.VERSION_1_8
20 | withSourcesJar()
21 | withJavadocJar()
22 | }
--------------------------------------------------------------------------------
/blink-ksp/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/blink-ksp/consumer-rules.pro
--------------------------------------------------------------------------------
/blink-ksp/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=blink-ksp
2 | POM_NAME=blink-ksp
3 | POM_DESCRIPTION=Blink navigator
--------------------------------------------------------------------------------
/blink-ksp/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/blink-ksp/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/blink-ksp/src/main/java/com/seewo/blink/fragment/ksp/BlinkMetadataEntry.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.ksp
2 |
3 | data class BlinkMetadataEntry(
4 | val packageName: String,
5 | val className: String,
6 | )
--------------------------------------------------------------------------------
/blink-ksp/src/main/java/com/seewo/blink/fragment/ksp/BlinkProcessorProvider.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.ksp
2 |
3 | import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
4 | import com.google.devtools.ksp.processing.SymbolProcessorProvider
5 |
6 | class BlinkProcessorProvider: SymbolProcessorProvider {
7 | override fun create(environment: SymbolProcessorEnvironment) = BlinkUriProcessor(environment)
8 | }
--------------------------------------------------------------------------------
/blink-ksp/src/main/java/com/seewo/blink/fragment/ksp/BlinkUriEntry.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.ksp
2 |
3 | data class BlinkUriEntry(
4 | val packageName: String,
5 | val className: String,
6 | val uris: List,
7 | )
--------------------------------------------------------------------------------
/blink-ksp/src/main/java/com/seewo/blink/fragment/ksp/BlinkUriProcessor.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.fragment.ksp
2 |
3 | import com.google.devtools.ksp.getClassDeclarationByName
4 | import com.google.devtools.ksp.processing.Dependencies
5 | import com.google.devtools.ksp.processing.Resolver
6 | import com.google.devtools.ksp.processing.SymbolProcessor
7 | import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
8 | import com.google.devtools.ksp.symbol.KSAnnotated
9 | import com.google.devtools.ksp.symbol.KSClassDeclaration
10 | import com.seewo.blink.annotation.BlinkMetadata
11 | import com.seewo.blink.annotation.BlinkUri
12 | import com.squareup.kotlinpoet.ClassName
13 | import com.squareup.kotlinpoet.FileSpec
14 | import com.squareup.kotlinpoet.FunSpec
15 |
16 | private const val FRAGMENT_ROUTE_MAP_CLASS = "com.seewo.blink.fragment.RouteMap"
17 | private const val ACTIVITY_ROUTE_MAP_CLASS = "com.seewo.blink.RouteMap"
18 |
19 | class BlinkUriProcessor(
20 | private val processingEnv: SymbolProcessorEnvironment
21 | ) : SymbolProcessor {
22 | private var round = 0
23 | private val logger = processingEnv.logger
24 | private val codeGenerator = processingEnv.codeGenerator
25 |
26 | override fun process(resolver: Resolver): List {
27 | if (round != 0) return emptyList()
28 |
29 | val metadataSymbols = resolver.getSymbolsWithAnnotation(BlinkMetadata::class.qualifiedName!!)
30 | val metadataElements = metadataSymbols.filterIsInstance()
31 | val metadataList = mutableListOf()
32 | metadataElements.forEach {
33 | val packageName = it.packageName.asString()
34 | val type = it.asType(emptyList())
35 | metadataList.add(BlinkMetadataEntry(packageName, type.toString()))
36 | }
37 | logger.warn("metadataList = $metadataList")
38 | val activityClass = resolver.getClassDeclarationByName("android.app.Activity")?.asType(emptyList()) ?: return emptyList()
39 | val fragmentClass = resolver.getClassDeclarationByName("androidx.fragment.app.Fragment")?.asType(emptyList())
40 | val fragmentRouteMap = resolver.getClassDeclarationByName(FRAGMENT_ROUTE_MAP_CLASS)
41 | val activityRouteMap = resolver.getClassDeclarationByName(ACTIVITY_ROUTE_MAP_CLASS)
42 |
43 | val symbols = resolver.getSymbolsWithAnnotation(BlinkUri::class.qualifiedName!!)
44 | val elements = symbols.filterIsInstance()
45 | val fragmentEntries = mutableListOf()
46 | val activityEntries = mutableListOf()
47 | elements.forEach {
48 | val packageName = it.packageName.asString()
49 | val type = it.asType(emptyList())
50 |
51 | if (fragmentClass?.isAssignableFrom(type) == true && fragmentRouteMap != null) {
52 | it.annotations.forEach { ks ->
53 | if (ks.shortName.asString() == BlinkUri::class.java.simpleName) {
54 | ks.arguments.forEach { arg ->
55 | if (arg.name?.asString() == "value") {
56 | logger.warn("bind ${arg.value} to $packageName.$type")
57 | val uris = if (arg.value is String) {
58 | listOf(arg.value as String)
59 | } else arg.value as List
60 | fragmentEntries.add(
61 | BlinkUriEntry(
62 | packageName, "$type", uris
63 | )
64 | )
65 | }
66 | }
67 | }
68 | }
69 | }
70 | if (activityClass.isAssignableFrom(type) && activityRouteMap != null) {
71 | it.annotations.forEach { ks ->
72 | if (ks.shortName.asString() == BlinkUri::class.java.simpleName) {
73 | ks.arguments.forEach { arg ->
74 | if (arg.name?.asString() == "value") {
75 | logger.warn("bind ${arg.value} to $packageName.$type")
76 | val uris = if (arg.value is String) {
77 | listOf(arg.value as String)
78 | } else arg.value as List
79 | activityEntries.add(
80 | BlinkUriEntry(
81 | packageName, "$type", uris
82 | )
83 | )
84 | }
85 | }
86 | }
87 | }
88 | }
89 | }
90 |
91 | metadataList.firstOrNull()?.let {
92 | val metadataClassName = "${it.packageName}.${it.className}"
93 | val metadata = ClassName(it.packageName, it.className)
94 | val fileSpec = FileSpec.builder("com.seewo.blink", "Initializer\$${metadataClassName.replace('.', '$')}")
95 | .addFunction(FunSpec.builder("_inject")
96 | .receiver(metadata)
97 | .apply {
98 | fragmentEntries.forEach {
99 | it.uris.forEach { uri ->
100 | addStatement("$FRAGMENT_ROUTE_MAP_CLASS.register(%S, %T::class.java)", uri, ClassName(it.packageName, it.className))
101 | }
102 | }
103 | activityEntries.forEach {
104 | it.uris.forEach { uri ->
105 | addStatement("$ACTIVITY_ROUTE_MAP_CLASS.register(%S, %T::class.java)", uri, ClassName(it.packageName, it.className))
106 | }
107 | }
108 | }
109 | .build())
110 | .build()
111 |
112 | codeGenerator.createNewFile(Dependencies.ALL_FILES, fileSpec.packageName, fileSpec.name).use {
113 | it.write(fileSpec.toString().toByteArray())
114 | }
115 | }
116 |
117 | round++
118 | return emptyList()
119 | }
120 | }
--------------------------------------------------------------------------------
/blink-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider:
--------------------------------------------------------------------------------
1 | com.seewo.blink.fragment.ksp.BlinkProcessorProvider
--------------------------------------------------------------------------------
/blink-utils/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/blink-utils/README.md:
--------------------------------------------------------------------------------
1 | # Blink-utils
2 |
3 | ## 主要功能
4 |
5 | - 目前仅包含一些快速操作Uri的扩展函数
6 |
7 | ## 具体说明
8 |
9 | ### 为Uri设置参数时,建议使用以下append方法,而不是Uri.Builder自带的appendQueryParameter方法,主要做以下几点处理
10 |
11 | 1. 可以正确的传入列表
12 | 2. 避免null被转为"null"或""传入到参数中,导致参数失真
13 | 3. 对于非String类型的一些常用数据类型,做了相关序列化处理
14 | 4. 目前支持的类型:基本类型,String,枚举,以上几种类型的列表
15 | 5. 复杂数据结构建议序列化为json后传入,或者转化成Intent后传入。
16 | 6. 庞大的数据不建议通过路由参数传递给页面,如有必要,建议通过静态对象等来传递
17 |
18 | ### append结合fun String.buildUri()和 fun Uri.build()两个扩展函数可以方便的对Uri进行修改和传参
19 |
20 | ## 使用示例
21 |
22 | #### 依赖引入
23 |
24 | blink-utils不需要单独引入,blink-activity和blink-fragment都包含了相关依赖
25 |
26 | #### 实际使用
27 |
28 | ```kotlin
29 | val uri = "scheme://my.app.com/index?id=seewo"
30 | val result = uri.buildUri {
31 | path("/home")
32 | append("page", 3)
33 | append("tag", null)
34 | }
35 | // 以上语句返回一个Uri给result,内容为: cheme://my.app.com/home?id=seewo&page=3
36 | ```
--------------------------------------------------------------------------------
/blink-utils/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | if (LOCAL_DEBUG.toBoolean()) {
7 | apply from: "${project.rootDir}/gradle/local-maven-push.gradle"
8 | } else {
9 | apply from: "${project.rootDir}/gradle/jitpack-push.gradle"
10 | // apply from: "${project.rootDir}/gradle/jfrog-push.gradle"
11 | }
12 |
13 | android {
14 | namespace 'com.seewo.blink.utils'
15 | compileSdk 33
16 |
17 | defaultConfig {
18 | minSdk 21
19 | targetSdk 28
20 |
21 | consumerProguardFiles "consumer-rules.pro"
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = '1.8'
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/blink-utils/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/blink-utils/consumer-rules.pro
--------------------------------------------------------------------------------
/blink-utils/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=blink-utils
2 | POM_NAME=blink-utils
3 | POM_DESCRIPTION=Blink navigator
--------------------------------------------------------------------------------
/blink-utils/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/blink-utils/src/androidTest/java/com/seewo/blink/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.seewo.blink.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/blink-utils/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/blink-utils/src/main/java/com/seewo/blink/utils/BlinkKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink.utils
2 |
3 | import android.net.Uri
4 |
5 |
6 | private fun Uri.Builder.appendQueryParameter(key: String, value: Any) = appendQueryParameter(key, "$value")
7 |
8 | /**
9 | * 为Uri设置参数时,建议使用以下append方法,而不是Uri.Builder自带的appendQueryParameter方法,主要做以下几点处理
10 | * 1. 可以正确的传入列表
11 | * 2. 避免null被转为"null"或""传入到参数中,导致参数失真
12 | * 3. 对于非String类型的一些常用数据类型,做了相关序列化处理
13 | * 4. 目前支持的类型:基本类型,String,枚举,以上几种类型的列表
14 | * 5. 复杂数据结构建议序列化为json后传入,或者转化成Intent后传入。
15 | * 6. 庞大的数据不建议通过路由参数传递给页面,如有必要,建议通过静态对象等来传递
16 | */
17 | fun Uri.Builder.append(key: String, value: Any?): Uri.Builder {
18 | value ?: return this
19 | if (value is Collection<*>) {
20 | if (value.isEmpty()) {
21 | return appendQueryParameter(key, "")
22 | } else {
23 | value.forEach { item ->
24 | item ?: return@forEach
25 | appendQueryParameter(key, item)
26 | }
27 | return this
28 | }
29 | }
30 | return appendQueryParameter(key, "$value")
31 | }
32 |
33 | /**
34 | * 在lambda中对Uri进行修改或参数追加
35 | */
36 | fun Uri.build(block: Uri.Builder.() -> Unit) = buildUpon().apply(block).build()
37 |
38 | /**
39 | * 在lambda中对Uri进行修改或参数追加
40 | */
41 | fun String.buildUri(block: Uri.Builder.() -> Unit) = Uri.parse(this).buildUpon().apply(block).build()
42 |
43 | /**
44 | * 获取Uri的主Uri,对于带参的Uri,即为?前的部分
45 | */
46 | val Uri.baseUri: String
47 | get() = "$scheme://$authority$path"
48 |
49 |
--------------------------------------------------------------------------------
/blink-utils/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/blink-utils/src/test/java/com/seewo/blink/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.blink
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext {
4 | getGitSha = {
5 | def sha = 'git rev-parse --short HEAD'.execute()
6 | sha.waitFor()
7 | if (sha.exitValue() != 0) {
8 | return ''
9 | }
10 | return sha.text.trim()
11 | }
12 | }
13 | // dependencies {
14 | // classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.24.12"
15 | // }
16 | }
17 |
18 | plugins {
19 | id 'com.android.application' version '7.4.2' apply false
20 | id 'com.android.library' version '7.4.2' apply false
21 | id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
22 | id 'com.google.devtools.ksp' version '1.6.21-1.0.6' apply false
23 | id 'org.jetbrains.kotlin.jvm' version '1.6.10' apply false
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
--------------------------------------------------------------------------------
/doc/logo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/doc/logo.jpeg
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 |
25 | LOCAL_DEBUG=false
26 |
27 | GITLAB_URL=https://gitlab.gz.cvte.cn/seewocbb/Blink
28 |
29 | POM_VERSION_NAME = 0.1.4
30 | POM_GROUP=com.seewo.library
31 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/gradle/deploy-local.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ./gradlew -p lib clean assembleRelease || { exit 1 ; }
4 | ./gradlew -p lib publishToMavenLocal || { exit 1 ; }
5 |
6 |
--------------------------------------------------------------------------------
/gradle/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ./gradlew -p blink-utils clean artifactoryPublish -Dusername=$1 -Dpassword=$2 -Dsnapshot=false || { exit 1 ; }
4 | ./gradlew -p blink-annotation clean artifactoryPublish -Dusername=$1 -Dpassword=$2 -Dsnapshot=false || { exit 1 ; }
5 | ./gradlew -p blink-ksp clean artifactoryPublish -Dusername=$1 -Dpassword=$2 -Dsnapshot=false || { exit 1 ; }
6 | ./gradlew -p blink-activity clean artifactoryPublish -Dusername=$1 -Dpassword=$2 -Dsnapshot=false || { exit 1 ; }
7 | ./gradlew -p blink-fragment clean artifactoryPublish -Dusername=$1 -Dpassword=$2 -Dsnapshot=false || { exit 1 ; }
8 |
9 |
--------------------------------------------------------------------------------
/gradle/jfrog-push-java.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'com.jfrog.artifactory'
3 |
4 |
5 | task sourcesJar(type: Jar) {
6 | from sourceSets.main.java
7 | archiveClassifier.set('sources')
8 | }
9 |
10 | artifactoryPublish.dependsOn('build')
11 |
12 | publishing {
13 | publications {
14 | mavenJava(MavenPublication) {
15 | groupId POM_GROUP
16 | version POM_VERSION_NAME + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
17 | artifactId POM_ARTIFACT_ID
18 | artifact "$buildDir/libs/${project.name}.jar"
19 | artifact sourcesJar
20 |
21 | pom.withXml {
22 | asNode().appendNode('description', POM_DESCRIPTION + ' Git commit:' + getGitSha())
23 | final depsNode = asNode().appendNode('dependencies')
24 |
25 | def compileDeps = configurations.api.getAllDependencies()
26 | // compileDeps += configurations.compile.getAllDependencies()
27 |
28 | def runtimeDeps = configurations.implementation.getAllDependencies()
29 | runtimeDeps -= compileDeps
30 |
31 | compileDeps.each {
32 | def dependencyNode = depsNode.appendNode('dependency')
33 | dependencyNode.appendNode('groupId', it.group)
34 | dependencyNode.appendNode('artifactId', it.name)
35 | dependencyNode.appendNode('version', it.version)
36 | dependencyNode.appendNode('scope', "compile")
37 | }
38 | runtimeDeps.each {
39 | def dependencyNode = depsNode.appendNode('dependency')
40 | dependencyNode.appendNode('groupId', it.group)
41 | dependencyNode.appendNode('artifactId', it.name)
42 | dependencyNode.appendNode('version', it.version)
43 | dependencyNode.appendNode('scope', "runtime")
44 | }
45 |
46 | if (depsNode.children().size() == 0) {
47 | asNode().remove(depsNode)
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | artifactory {
55 | contextUrl = "https://artifactory.gz.cvte.cn/artifactory"
56 | publish {
57 | repository {
58 | repoKey = Boolean.valueOf(System.getProperty("snapshot")) ? "SR_maven_snapshots_local" : "SR_maven_releases_local"
59 | username = System.getProperty("username")
60 | password = System.getProperty("password")
61 | }
62 | defaults {
63 | publications('mavenJava')
64 | publishArtifacts = true
65 | publishPom = true
66 | properties = ['gitlab_url': GITLAB_URL, 'vcs.revision': System.getProperty("vcs")]
67 | }
68 | }
69 | }
70 |
71 | artifacts {
72 | archives sourcesJar
73 | }
74 |
--------------------------------------------------------------------------------
/gradle/jfrog-push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'com.jfrog.artifactory'
3 |
4 | task androidJavadocs(type: Javadoc) {
5 | source = android.sourceSets.main.java.srcDirs
6 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
7 | }
8 |
9 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
10 | getArchiveClassifier().set('javadoc')
11 | from androidJavadocs.destinationDir
12 | }
13 |
14 | task androidSourcesJar(type: Jar) {
15 | getArchiveClassifier().set('sources')
16 | from android.sourceSets.main.java.srcDirs
17 | }
18 |
19 | artifactoryPublish.dependsOn('assembleRelease')
20 |
21 | publishing {
22 | publications {
23 | aar(MavenPublication) {
24 | groupId POM_GROUP
25 | version POM_VERSION_NAME + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
26 | artifactId POM_ARTIFACT_ID
27 | artifact "$buildDir/outputs/aar/${project.name}-release.aar"
28 | artifact androidSourcesJar
29 |
30 | pom.withXml {
31 | asNode().appendNode('description', POM_DESCRIPTION + ' Git commit:' + getGitSha())
32 | final depsNode = asNode().appendNode('dependencies')
33 |
34 | def compileDeps = configurations.api.getAllDependencies()
35 |
36 | def runtimeDeps = configurations.implementation.getAllDependencies()
37 | runtimeDeps -= compileDeps
38 | //
39 | compileDeps.each {
40 | def dependencyNode = depsNode.appendNode('dependency')
41 | dependencyNode.appendNode('groupId', it.group)
42 | dependencyNode.appendNode('artifactId', it.name)
43 | dependencyNode.appendNode('version', it.version)
44 | dependencyNode.appendNode('scope', "compile")
45 | }
46 | runtimeDeps.each {
47 | def dependencyNode = depsNode.appendNode('dependency')
48 | dependencyNode.appendNode('groupId', it.group)
49 | dependencyNode.appendNode('artifactId', it.name)
50 | dependencyNode.appendNode('version', it.version)
51 | dependencyNode.appendNode('scope', "runtime")
52 | }
53 | if (depsNode.children().size() == 0) {
54 | asNode().remove(depsNode)
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
61 | artifactory {
62 | contextUrl = "https://artifactory.gz.cvte.cn/artifactory"
63 | publish {
64 | repository {
65 | repoKey = Boolean.valueOf(System.getProperty("snapshot")) ? "SR_maven_snapshots_local" : "SR_maven_releases_local"
66 | username = System.getProperty("username")
67 | password = System.getProperty("password")
68 | }
69 | defaults {
70 | publications('aar')
71 | properties = ['gitlab_url': GITLAB_URL, 'vcs.revision': System.getProperty("vcs")]
72 | }
73 | }
74 | }
75 |
76 | artifacts {
77 | archives androidSourcesJar
78 | }
79 |
--------------------------------------------------------------------------------
/gradle/jitpack-push-java.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 |
3 | afterEvaluate {
4 | publishing {
5 | publications {
6 | release(MavenPublication) {
7 | from components.java
8 | groupId = POM_GROUP
9 | artifactId = POM_ARTIFACT_ID
10 | version = POM_VERSION_NAME + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
11 | }
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/gradle/jitpack-push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 |
3 | task sourceJar(type: Jar) {
4 | from android.sourceSets.main.java.srcDirs
5 | archiveClassifier = "sources"
6 | }
7 |
8 | afterEvaluate {
9 | publishing {
10 | publications {
11 | release(MavenPublication) {
12 | from components.release
13 | artifact sourceJar
14 | groupId = POM_GROUP
15 | artifactId = POM_ARTIFACT_ID
16 | version = POM_VERSION_NAME + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/gradle/local-maven-push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 |
3 | publishing {
4 | publications {
5 | maven(MavenPublication) {
6 | groupId = POM_GROUP
7 | artifactId = POM_ARTIFACT_ID
8 | version = POM_VERSION_NAME
9 | artifact "$buildDir/outputs/aar/${project.name}-release.aar"
10 |
11 | // pom.withXml {
12 | // asNode().appendNode('description', POM_DESCRIPTION + ' Git commit:' + getGitSha())
13 | // final depsNode = asNode().appendNode('dependencies')
14 | //
15 | // def compileDeps = configurations.api.getAllDependencies()
16 | // compileDeps += configurations.compile.getAllDependencies()
17 | //
18 | // def runtimeDeps = configurations.implementation.getAllDependencies()
19 | // runtimeDeps -= compileDeps
20 | //
21 | // compileDeps.each {
22 | // def dependencyNode = depsNode.appendNode('dependency')
23 | // dependencyNode.appendNode('groupId', it.group)
24 | // dependencyNode.appendNode('artifactId', it.name)
25 | // dependencyNode.appendNode('version', it.version)
26 | // dependencyNode.appendNode('scope', "compile")
27 | // }
28 | // runtimeDeps.each {
29 | // def dependencyNode = depsNode.appendNode('dependency')
30 | // dependencyNode.appendNode('groupId', it.group)
31 | // dependencyNode.appendNode('artifactId', it.name)
32 | // dependencyNode.appendNode('version', it.version)
33 | // dependencyNode.appendNode('scope', "runtime")
34 | // }
35 | // if (depsNode.children().size() == 0) {
36 | // asNode().remove(depsNode)
37 | // }
38 | // }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/Blink/6032d13e7342cff60c1f4377d01c2b9f6ac77a66/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Apr 14 15:03:30 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | # configuration file for building snapshots and releases with jitpack.io
2 | jdk:
3 | - openjdk11
4 | before_install:
5 | - ./scripts/prepareJitpackEnvironment.sh
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven { url 'https://maven.aliyun.com/repository/google' } // google()
4 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } // maven { url "https://plugins.gradle.org/m2/" }
5 | maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
6 | gradlePluginPortal()
7 | }
8 | }
9 | dependencyResolutionManagement {
10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
11 | repositories {
12 | maven { url 'https://maven.aliyun.com/repository/public' } // jcenter()
13 | maven { url 'https://maven.aliyun.com/repository/google' } // google()
14 | maven { url 'https://maven.aliyun.com/repository/central' } // mavenCentral()
15 | }
16 | }
17 | rootProject.name = "Blink"
18 |
19 | include ':blink-annotation'
20 | include ':blink-ksp'
21 |
22 | include ':blink-utils'
23 | include ':blink-fragment'
24 | include ':blink-activity'
25 |
26 | include ':app'
27 |
--------------------------------------------------------------------------------