├── .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 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 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/v/robin8yeung/Blink.svg)](https://jitpack.io/#robin8yeung/Blink) 4 | [![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](./LICENSE) 5 | 6 | Blink的名字取自dota中的"闪烁Blink"技能,敌法师、痛苦女王等英雄通过闪烁技能可以闪现到指定位置。 7 | 8 | ![LOGO](doc/logo.jpeg) 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/v/robin8yeung/Blink.svg)](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 |