diff --git a/README.md b/README.md index 9f023c5..e78eca3 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,22 @@ -# 电商平台深度链接示例 +# Deeolink -仓库提供了一个 Android 示例应用,展示如何在不申请额外权限的情况下,从应用内一键跳转到京东、淘宝、天猫、亚马逊、拼多多等主流电商平台的指定页面。 +一个轻量级的 Android Library,用于在无需额外权限的前提下,统一调起京东、淘宝、天猫、亚马逊、拼多多等常见电商平台的客户端。当对应 App 不存在时,会自动回退到浏览器打开相同页面。 -## Jenkins相关 +## 快速集成 -保姆级教程: [从零搭建 Jenkins Android 自动发包体系](https://yuuou.vercel.app/%E4%B8%9A%E5%8A%A1%E6%80%9D%E8%80%83/%E4%BB%8E%E9%9B%B6%E6%90%AD%E5%BB%BA%20Jenkins%20Android%20%E8%87%AA%E5%8A%A8%E5%8F%91%E5%8C%85%E4%BD%93%E7%B3%BB) +在 `build.gradle` 中添加依赖: -具体代码可查看 [pipeline](./jenkins/pipeline) - -## 功能亮点 - -- 📦 **内置多家电商配置**:预置多个平台的包名与示例链接,可直接体验或替换为自己的链接。 -- 🚀 **统一调起能力**:根据已安装的 App 自动选择最优平台,若未安装则回退到浏览器打开 H5 页面。 -- 🔒 **无需额外权限**:通过深度链接协议调起,无需在运行时申请敏感权限。 -- 🧩 **易于扩展**:仅需配置 `packageName` 与目标 URL,即可新增或替换商家入口。 - -## 快速开始 - -1. **克隆项目并导入** - - 使用 `git clone` 下载仓库,或直接在 Android Studio 中选择 *Get from VCS*。 - - 使用 Android Studio 打开项目根目录后,会自动完成 Gradle 同步。 - -2. **运行示例应用** - - 连接一台已安装目标电商平台的 Android 设备或启动模拟器。 - - 编译并运行 `app` 模块,在首页选择对应平台即可验证调起效果。 - -3. **自定义店铺或商品链接** - - 打开 [`AppLauncherUtils.kt`](app/src/main/java/yuu/deeplink/AppLauncherUtils.kt),修改 `shopData` 中各平台的 `url` 字段即可替换跳转目标。 - - 如需新增平台,可新增一条 `ShopInfo` 配置,并在 `SHOP_PRIORITY_ORDER` 中指定优先级。 - -## 实现原理 - -深度链接调起流程主要包含以下步骤: +```kotlin +dependencies { + implementation("io.github.yuuouu:deeolink:1.0.0") +} +``` -1. **解析第三方 App 的入口配置**: - - 通过反编译目标 App,阅读 `AndroidManifest.xml`,定位 `` 中的深度链接规则(常见为 `http/https` scheme)。 -2. **准备目标链接**: - - 在目标 App 内点击分享或复制链接,确认其与 Manifest 中的规则匹配,例如 `https://mall.jd.com/index-1000000127.html`。 -3. **封装跳转逻辑**: - - 在项目中创建 `ShopInfo(packageName, url, displayName)`,并根据用户选择构造 `Intent.ACTION_VIEW` 去调起对应 App。 -4. **适配 App 安装状态**: - - 在尝试启动前先检测包是否存在,未安装时回退到系统浏览器打开同一链接,保证流程可用性。 +> 该坐标通过 Maven Central 发布,模块源码位于本仓库的 `deeolink` 目录。 -## 必要的清单配置 +### Manifest 配置 -为确保应用能够发现并调用其他 App,需要在主模块的 `AndroidManifest.xml` 中声明 `queries`: +Android 11 及以上版本需要显式声明可查询的包名,请在宿主 App 的 `AndroidManifest.xml` 中加入: ```xml @@ -56,10 +28,50 @@ ``` -如果新增或修改平台,记得同步更新清单配置,避免在 Android 11 及以上版本无法查询到目标 App。 +### 调用示例 -## 常见问题 +```kotlin +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // 指定平台 + AppLauncherUtils.openShop(this, AppLauncherUtils.TAOBAO) + + // 或按照默认优先级 (京东/淘宝/天猫/亚马逊/拼多多) 自动选择 + AppLauncherUtils.openShop(this) + } +} +``` + +## 自定义扩展 + +`AppLauncherUtils` 内置了多个 `ShopInfo` 配置,包含包名、深度链接示例与展示名称。若需要新增或覆盖默认行为,可在应用初始化阶段调用: + +```kotlin +val customShop = ShopInfo( + packageName = "com.example.shop", + url = "https://example.com/target", + displayNameRes = R.string.shop_name_example +) + +AppLauncherUtils.registerShop("custom_shop", customShop) +AppLauncherUtils.setPriorityOrder(listOf("custom_shop") + AppLauncherUtils.priorityOrder()) +``` + +如不再需要某个平台,可使用 `AppLauncherUtils.removeShop("custom_shop")` 移除配置。 + +## 发布说明 + +- Group Id:`io.github.yuuouu` +- Artifact Id:`deeolink` +- Version:`1.0.0` +- 发布仓库:Maven Central(含 sources.jar) + +如需本地调试发布流程,可执行: + +```bash +./gradlew publishReleasePublicationToSonatypeRepository +``` -- **为什么没有反应?** 请确认目标 App 是否安装,或查看 Logcat 是否有 `open_shop` 相关日志。 -- **如何扩展到更多平台?** 拿到目标 App 的包名与可匹配的深度链接,按照上文的方式在 `shopData` 中补充即可。 -- **能否在 WebView 中使用?** 只要能够触发上述跳转逻辑,即可复用;注意在 WebView 环境下同样需要检查设备是否安装目标 App。 \ No newline at end of file +在提供 PGP 签名信息与 Sonatype 账号后,即可将构件上传到 OSSRH 并同步到 Maven Central。 diff --git a/app/.gitignore b/app/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts deleted file mode 100644 index 2d0ab29..0000000 --- a/app/build.gradle.kts +++ /dev/null @@ -1,63 +0,0 @@ -plugins { - alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) -} - -android { - namespace = "yuu.deeplink" - - signingConfigs { - create("testRelease") { - val keystorePropertiesFile = rootProject.file("app/deeplink.jks") - storeFile = keystorePropertiesFile - storePassword = "deeplink" - keyAlias = "2333" - keyPassword = "deeplink" - } - create("testDebug") { - storeFile = file("app/deeplink.jks") - storePassword = "deeplink" - keyAlias = "2333" - keyPassword = "deeplink" - } - } - - - compileSdk = 34 - - defaultConfig { - applicationId = "yuu.deeplink" - minSdk = 30 - targetSdk = 34 - versionCode = 1 - versionName = "1.0" - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - isMinifyEnabled = false - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } -} - -dependencies { - - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.appcompat) - implementation(libs.material) - implementation(libs.androidx.activity) - implementation(libs.androidx.constraintlayout) - testImplementation(libs.junit) - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) -} \ No newline at end of file diff --git a/app/deeplink.jks b/app/deeplink.jks deleted file mode 100644 index e80b4b7..0000000 Binary files a/app/deeplink.jks and /dev/null differ diff --git a/app/src/androidTest/java/yuu/deeplink/ExampleInstrumentedTest.kt b/app/src/androidTest/java/yuu/deeplink/ExampleInstrumentedTest.kt deleted file mode 100644 index 47025e9..0000000 --- a/app/src/androidTest/java/yuu/deeplink/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package yuu.deeplink - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("yuu.deeplink", appContext.packageName) - } -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml deleted file mode 100644 index db16ff2..0000000 --- a/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/yuu/deeplink/MainActivity.kt b/app/src/main/java/yuu/deeplink/MainActivity.kt deleted file mode 100644 index f548350..0000000 --- a/app/src/main/java/yuu/deeplink/MainActivity.kt +++ /dev/null @@ -1,39 +0,0 @@ -package yuu.deeplink - -import android.os.Bundle -import android.widget.Button -import androidx.activity.enableEdgeToEdge -import androidx.appcompat.app.AppCompatActivity - - -class MainActivity: AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enableEdgeToEdge() - setContentView(R.layout.activity_main) - - findViewById