解锁Android的隐藏超链接:Deep Link与App Link探秘

解锁Android的隐藏超链接:Deep Link与App Link探秘

引言:开启深度链接的奇妙世界

在移动互联网的世界里,你是否常常遇到这样的场景:收到银行的转账短信,点击其中的链接,就能直接打开手机银行 App 并跳转到交易详情页面;又或是在朋友圈看到朋友分享的一篇精彩文章,来自某个资讯 App,点击链接后,神奇地直接唤起了该 App 并定位到对应的文章内容。这些看似平常的操作,背后却隐藏着一项强大的技术 ------ 深度链接(Deep Link)。

深度链接,简单来说,就是一种能够让用户从一个应用(如短信、网页、社交媒体等)直接跳转到另一个应用内特定页面的技术,它打破了应用之间的壁垒,为用户提供了更加便捷、流畅的体验,就像是在不同的数字城堡之间搭建了一条条秘密通道,让用户可以快速穿梭其中。

而在 Android 系统中,有两种重要的深度链接实现方式,它们就像深度链接世界里的两员大将,各有所长,这就是 Android Deep Link 和 App Link。接下来,就让我们一起深入探索它们的奥秘,揭开深度链接的神秘面纱 。

Android Deep Link:通用但存瑕的元老

核心原理:城堡的秘密密道

Android Deep Link,也被称为 URL Scheme,是深度链接技术中的 "元老",自 Android 系统诞生之初便已存在 。如果把每个 App 比作一座独立的城堡,那么 URL Scheme 就像是为每个城堡设计的 "秘密密道",它有着特殊的暗号格式,比如知乎的密道暗号是zhihu://

其工作机制也不难理解,应用首先要向操作系统 "登记" 自己的密道暗号。当系统遇到类似zhihu://questions/123456这样的暗号时,就会在已安装的应用中寻找所有能 "听懂" 这个暗号的 App,然后弹出一个选择器,询问用户 "你要用哪个城堡的密道?",也就是让用户选择使用哪个应用来打开这个链接。

短信场景中的应用

短信场景是 Android Deep Link 最常见的应用领域之一。例如,你收到银行发送的转账通知短信,内容可能是这样:

html 复制代码
尊敬的客户,您尾号8888的储蓄卡收入5000.00元。
<a href="icbc://transfer/result?order=20240119001">点击查看详情</a>
立即下载:<a href="https://appstore/icbc">应用商店</a>

在这条短信中,<a href="icbc://transfer/result?order=20240119001">点击查看详情</a>就是一个 Deep Link 链接。当用户点击这个链接时,如果手机上已经安装了工商银行的手机银行 App,系统就会尝试打开该 App,并将用户直接带到转账结果详情页面;如果未安装,则会显示无法打开的提示。这种方式为用户提供了极大的便利,无需手动打开 App 再去查找相关交易记录,大大提升了操作效率和用户体验。

实现方式全解析

  • H5 页面触发跳转:在 H5 页面中,有多种方法可以触发 Deep Link 跳转。

    • 直接跳转 :使用window.location.href属性直接赋值为 Deep Link 链接,如:
javascript 复制代码
function openAppByScheme() {
    window.location.href = 'zhihu://question/123456';
}
  • 通过 iframe 跳转:这种方式更加稳定,创建一个隐藏的 iframe,将 Deep Link 链接设置为其 src 属性,代码如下:
javascript 复制代码
function openAppByIframe() {
    const iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    iframe.src = 'zhihu://question/123456';
    document.body.appendChild(iframe);
    // 2秒后移除iframe
    setTimeout(() => {
        document.body.removeChild(iframe);
    }, 2000);
}
  • 处理短信链接 :在短信中,链接通常是直接可点击的,用户点击<a href="zhihu://question/123">短信链接</a>即可触发跳转,前端无需额外的复杂处理。

  • Android 原生端配置 :在 Android 原生开发中,需要在AndroidManifest.xml文件中进行配置,以声明应用对特定 Deep Link 的处理能力。

xml 复制代码
<!-- 接收Scheme链接的Activity -->
<activity android:name=".DeepLinkActivity"
          android:exported="true">
    <!-- 声明Scheme处理能力 -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- 声明你的密道暗号 -->
        <data
            android:host="deeplink"
            android:scheme="zhihu" />
        <!-- 可选:更精确的路径匹配 -->
        <data android:pathPrefix="/question/" />
    </intent-filter>
    <!-- 可以声明多个intent-filter处理不同格式 -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- 另一个Scheme -->
        <data android:scheme="zh" />
    </intent-filter>
</activity>

在上述配置中,<intent-filter>标签用于声明该 Activity 能够处理的 Intent 类型。<action android:name="android.intent.action.VIEW" />表示该 Activity 可以处理查看的动作;<category android:name="android.intent.category.DEFAULT" />允许 Activity 被隐式 Intent 启动;<category android:name="android.intent.category.BROWSABLE" />至关重要,它允许从浏览器中安全地启动该 Activity;<data>标签则定义了 URI 模式,包括android:scheme(协议,如zhihu)、android:host(主机名,如deeplink)以及android:pathPrefix(路径前缀,如/question/)等,用于精确匹配不同的链接格式。

  • 在 Activity 中处理传入的链接:当 Activity 接收到 Deep Link 对应的 Intent 时,需要对其进行处理,以实现跳转到相应的页面或执行特定的操作。
java 复制代码
public class DeepLinkActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_deeplink);
        // 处理传入的Intent
        handleDeepLink(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // 防止重复创建Activity
        setIntent(intent);
        handleDeepLink(intent);
    }

    private void handleDeepLink(Intent intent) {
        Uri uri = intent.getData();
        if (uri != null) {
            String uriString = uri.toString();
            if (uriString.startsWith("zhihu://question/")) {
                String questionId = uri.getLastPathSegment();
                openQuestionDetail(questionId);
            } else if (uriString.startsWith("zhihu://user/")) {
                String userId = uri.getLastPathSegment();
                openUserProfile(userId);
            } else if (uriString.startsWith("icbc://")) {
                handleBankTransaction(uri);
            }
        }
    }

    private void openQuestionDetail(String questionId) {
        // 跳转到问题详情页
        Intent intent = new Intent(this, QuestionDetailActivity.class);
        intent.putExtra("QUESTION_ID", questionId);
        startActivity(intent);
        finish();
    }

    private void openUserProfile(String userId) {
        // 跳转到用户主页
        Intent intent = new Intent(this, UserProfileActivity.class);
        intent.putExtra("USER_ID", userId);
        startActivity(intent);
        finish();
    }

    private void handleBankTransaction(Uri uri) {
        // 处理银行交易相关逻辑
    }
}

在上述代码中,handleDeepLink方法通过判断 Uri 的前缀来确定链接类型,然后根据不同的链接类型解析出相应的参数,并跳转到对应的页面或执行相应的操作。例如,对于知乎的问题链接,解析出问题 ID 并跳转到问题详情页面;对于用户主页链接,解析出用户 ID 并跳转到用户主页。

优缺点大剖析

  • 优点

    • 兼容性极佳:从 Android 1.0 到最新版本,都对 Android Deep Link 提供了良好的支持,这使得它在各种版本的 Android 设备上都能稳定运行,无需担心兼容性问题。

    • 实现简单 :开发者只需在AndroidManifest.xml中进行简单的配置,声明应用支持的 URL Scheme,即可实现基本的 Deep Link 功能,无需复杂的服务器配置或额外的技术栈。

    • 短信友好 :在短信中使用 Deep Link 非常方便,直接嵌入scheme://path格式的链接,用户点击即可跳转,无需对短信进行特殊处理,也不需要借助其他第三方工具。

  • 缺点

    • 弹出选择器:由于多个应用可以声明相同的自定义 Scheme,当用户点击 Deep Link 链接时,系统会弹出选择器,询问用户使用哪个应用打开链接。这不仅增加了用户的操作步骤,还破坏了用户体验的流畅性,尤其是在用户明确知道想要打开的应用时,这种选择器显得多余。

    • 无法判断是否成功:在 H5 页面触发 Deep Link 跳转时,无法准确判断应用是否成功打开。虽然可以使用定时器方案来进行大致判断,但这种方法并不准确,存在一定的误差,无法满足对跳转结果精确判断的需求。

    • 容易被劫持:恶意应用可以注册与合法应用相同的 Scheme,从而劫持 Deep Link 链接。当用户点击链接时,可能会被引导至恶意应用,导致信息泄露、安全风险增加等问题,给用户和合法应用开发者带来损失。

    • 微信 / QQ 中被屏蔽:在微信、QQ 等社交应用中,为了保障用户安全和应用生态的健康,会拦截非白名单的 Scheme 链接。这使得 Android Deep Link 在这些主流社交平台上无法正常使用,限制了其传播和推广的范围。

    • 无降级方案:如果用户手机上未安装对应的应用,点击 Deep Link 链接后会直接显示无法打开的提示,没有提供合理的降级方案,比如跳转到应用商店进行下载,这会导致用户体验的中断,降低用户对应用的好感度。

综上所述,Android Deep Link 虽然具有兼容性好、实现简单等优点,但也存在诸多缺点,在实际应用中需要根据具体场景和需求谨慎使用,并结合其他技术来弥补其不足 。

Android App Link:官方出品的优雅方案

核心原理:基于域名的所有权验证

如果说 Android Deep Link 是民间的 "小道密道",那么 Android App Link 则是官方打造的 "高速公路",更加规范、安全、高效 。App Link 是 Android 6.0(API 级别 23)引入的一种深度链接技术,它的出现主要是为了解决 Android Deep Link 存在的一些问题,如弹出选择器、安全性低等 。

App Link 基于 HTTP/HTTPS 协议,其核心原理是通过验证应用对某个域名的所有权,来实现无歧义的深度链接。简单来说,就是应用需要向系统证明自己是某个域名的合法拥有者,这样当用户点击指向该域名的链接时,系统就会直接打开对应的应用,而不会弹出选择器询问用户 。

为了便于理解,我们可以将这个过程想象成一个快递配送系统。每个 App 就像是一个收件人,而链接中的域名则是收件地址。在普通的配送方式(类似 Android Deep Link)中,当快递员(系统)拿到一个包裹(链接)时,由于有多个收件人(应用)可能声称对这个地址有接收权,快递员就会询问周围的人(弹出选择器):"这个包裹该给谁?" 而在 App Link 的 "官方快递系统" 中,收件人(应用)提前向快递站(系统)提供了自己的指纹信息(通过域名所有权验证),当快递员拿到包裹时,只需要核对指纹(验证域名所有权),如果匹配,就可以直接将包裹送到收件人手中,无需再询问其他人 。

具体的验证流程如下:

  1. 在 AndroidManifest.xml 中声明 :应用首先需要在AndroidManifest.xml文件中声明支持的 HTTP/HTTPS Intent Filter,例如:
xml 复制代码
<activity android:name=".AppLinkActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="example.com"
            android:pathPrefix="/article/" />
    </intent-filter>
</activity>

在上述代码中,android:autoVerify="true"表示应用请求系统在安装时自动验证其对指定域名的所有权;<data>标签定义了应用能够处理的链接格式,包括android:scheme(协议,必须是 http 或 https)、android:host(主机名,即域名)以及android:pathPrefix(路径前缀,用于更精确地匹配链接) 。

  1. 在网站上发布验证文件 :应用开发者需要在对应的网站上发布一个 Digital Asset Links JSON 文件(通常位于/.well-known/assetlinks.json),该文件包含了应用的包名和签名证书的 SHA-256 指纹等信息,用于证明应用对该域名的所有权 。例如:
json 复制代码
[{
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
        "namespace": "android_app",
        "package_name": "com.example.app",
        "sha256_cert_fingerprints": ["ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890"]
    }
}]
  1. 系统验证:当用户安装应用时,系统会自动下载并验证这个 JSON 文件。如果验证成功,系统就会将该应用与对应的域名关联起来。此后,当用户点击指向该域名的链接时,系统就会直接打开对应的应用,并将链接传递给应用进行处理 。

实现步骤详解

  • 配置 AndroidManifest.xml :在AndroidManifest.xml中,为需要处理 App Link 的 Activity 添加intent-filter,示例如下:
xml 复制代码
<activity android:name=".AppLinkActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="example.com"
            android:pathPrefix="/article/" />
        <!-- 可以添加多个data标签,以支持不同的链接格式 -->
        <data
            android:scheme="https"
            android:host="example.com"
            android:pathPrefix="/user/" />
    </intent-filter>
</activity>
  • 配置服务器端 :在服务器上创建并放置assetlinks.json文件,文件内容格式如下:
json 复制代码
[{
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
        "namespace": "android_app",
        "package_name": "com.example.app",
        "sha256_cert_fingerprints": ["YOUR_SHA256_CERT_FINGERPRINT"]
    }
}]

其中,YOUR_SHA256_CERT_FINGERPRINT需要替换为应用签名证书的 SHA-256 指纹。获取 SHA-256 指纹的方法如下:

  • 使用命令行工具:如果是使用 Gradle 构建的项目,可以在项目根目录下的命令行中执行以下命令(假设使用的是 JDK 1.8 及以上版本):
bash 复制代码
./gradlew signingReport

在输出结果中,找到对应构建类型(如releasedebug)的SHA-256指纹。

  • 使用 Android Studio :在 Android Studio 中,依次点击Build -> Generate Signed Bundle / APK,按照向导完成操作。在最后一步,点击View Certificate,即可查看证书的详细信息,包括 SHA-256 指纹 。

优势尽显

  • 无歧义直接打开:由于通过域名所有权验证,系统能够明确知道应该使用哪个应用来打开链接,避免了弹出选择器的困扰,为用户提供了更加流畅、无缝的体验,就像快递直接送达收件人手中,无需中间的询问环节 。

  • 无缝体验:用户从外部链接直接进入应用内的特定页面,整个过程自然流畅,无需额外的操作,大大提升了用户体验,增强了用户对应用的好感度 。

  • 安全性高:基于 HTTP/HTTPS 协议和域名所有权验证,有效防止了链接被劫持,保障了用户的信息安全和应用的正常使用,就像给快递加上了一把安全锁 。

  • SEO 友好:使用标准的 HTTP/HTTPS 链接,有利于搜索引擎对应用内容的索引和收录,提高应用的曝光率和可发现性 。

  • 未安装处理:如果用户未安装应用,点击 App Link 链接时,系统会自然降级到对应的网页,为用户提供了合理的备用方案,避免了用户体验的中断 。

当然,App Link 也并非完美无缺,它也存在一些不足之处:

  • 配置相对复杂:相比 Android Deep Link,App Link 的配置过程涉及到服务器端的配置和域名所有权验证,对于开发者来说,需要更多的技术知识和操作步骤 。

  • 版本限制:App Link 仅支持 Android 6.0(API 级别 23)及以上版本的系统,这意味着在一些老旧设备上无法使用,限制了其应用范围 。

  • 国内特殊环境:在国内,由于网络环境和应用生态的特殊性,可能会存在一些兼容性问题或无法正常验证域名所有权的情况,需要开发者进行额外的适配和调试 。

总体而言,Android App Link 以其独特的优势,为深度链接带来了更加优质的解决方案,尤其适用于追求极致用户体验和高安全性的应用场景 。

两者深度对比:差异与选择

在深入了解了 Android Deep Link 和 App Link 之后,我们来对它们进行一番全面的对比,以便在实际开发中能够根据项目的具体需求做出明智的选择 。

对比维度 Android Deep Link Android App Link
适用版本 全系列版本,从 Android 1.0 起就已存在,兼容性极佳,能够覆盖所有 Android 设备,无论是老旧机型还是最新款手机,都能稳定支持 Deep Link 功能 仅支持 Android 6.0(API 级别 23)及以上版本,在一些运行 Android 6.0 以下系统的设备上无法使用,这在一定程度上限制了其应用范围 ,但随着 Android 系统的不断更新换代,高版本系统的设备占比逐渐增加,App Link 的应用场景也在不断扩大
适用协议 支持自定义协议,开发者可以根据项目需求自由定义 URL Scheme,如myapp:// ,这种灵活性使得 Deep Link 在一些特定场景下能够更好地满足业务需求,例如在企业内部应用中,可以使用自定义协议来实现特定功能的深度链接 仅支持 HTTP/HTTPS 协议,基于标准的网络协议,这使得 App Link 在安全性和通用性方面具有优势,同时也有利于与 Web 端进行无缝集成,方便进行 SEO 优化和跨平台交互
安全验证 不进行验证,这使得 Deep Link 存在一定的安全风险,恶意应用可以注册相同的自定义 Scheme,从而劫持链接,导致用户被引导至恶意应用,造成信息泄露、安全威胁等问题 需要进行客户端与服务器端的双向验证,通过在服务器上放置 Digital Asset Links JSON 文件,验证应用对域名的所有权,确保链接只能被指定的应用处理,有效防止了链接被劫持,保障了用户的信息安全和应用的正常使用 ,就像给链接加上了一把坚固的安全锁
用户体验 通常会弹出选择器,当多个应用声明相同的自定义 Scheme 时,系统会询问用户使用哪个应用打开链接,这增加了用户的操作步骤,破坏了用户体验的流畅性,尤其是在用户明确知道想要打开的应用时,这种选择器显得多余 默认直接启动目标 App,用户点击链接后能够直接进入应用内的特定页面,无需额外的操作,提供了更加流畅、无缝的用户体验,就像乘坐直达电梯一样,快速到达目的地
实现难度 实现相对简单,只需在AndroidManifest.xml中进行简单的配置,声明应用支持的 URL Scheme 即可,无需复杂的服务器配置或额外的技术栈,对于开发者来说,上手难度较低 配置相对复杂,除了在AndroidManifest.xml中进行配置外,还需要在服务器端创建并放置assetlinks.json文件,进行域名所有权验证,这需要开发者具备一定的服务器端开发知识和操作经验 ,但一旦配置完成,能够为应用带来更优质的深度链接体验
未安装处理 无合理的降级方案,如果用户手机上未安装对应的应用,点击 Deep Link 链接后会直接显示无法打开的提示,导致用户体验的中断,无法引导用户进行进一步的操作,如下载应用 有合理的降级方案,如果用户未安装应用,点击 App Link 链接时,系统会自然降级到对应的网页,用户可以在网页上进行相关操作,或者引导用户下载应用,为用户提供了更加友好的体验,避免了用户体验的中断 ,就像为用户准备了一条备用通道
通过以上对比可以看出,Android Deep Link 和 App Link 各有优劣。在实际项目中,如果需要兼容所有 Android 版本,或者对链接的灵活性有较高要求,且对安全性和用户体验的要求相对较低,可以选择使用 Android Deep Link;如果项目主要面向 Android 6.0 及以上版本的设备,追求极致的用户体验和高安全性,并且愿意投入更多的时间和精力进行配置,那么 Android App Link 无疑是更好的选择 。在一些情况下,也可以同时使用两者,利用 Deep Link 的兼容性和 App Link 的优势,为用户提供更加全面、优质的深度链接服务 。

实践建议与避坑指南

在实际项目中使用 Android Deep Link 和 App Link 时,以下是一些实用的建议和需要注意的问题 。

同步配置两者

为了确保在不同的 Android 版本和场景下都能提供良好的深度链接体验,建议同时配置 Android Deep Link 和 App Link 。以电商 App 为例,在进行营销活动时,通过短信向用户发送活动链接。如果只配置了 App Link,那么在 Android 6.0 以下版本的设备上,链接将无法正常工作,导致用户无法参与活动,从而影响活动效果和用户体验 。而如果同时配置了 Deep Link,即使在低版本设备上,也能通过 Deep Link 实现基本的跳转功能,保证了活动的覆盖范围和用户参与度 。

点击链接无反应

  • 原因 :最常见的原因是没有匹配到 Intent Filter,可能是 scheme、host、path 等配置与实际链接不一致 。例如,在配置 Intent Filter 时,将 scheme 声明为myapp,而实际链接中使用的是myApp(注意大小写),这样就会导致无法匹配,点击链接无反应 。

  • 解决方案 :仔细检查AndroidManifest.xml中 Intent Filter 的配置,确保与链接中的 scheme、host、path 等完全一致,包括大小写 。可以使用 ADB 命令进行测试,如adb shell am start -a android.intent.action.VIEW -d "myapp://detail?id=123",如果能成功打开应用,则说明配置正确;如果提示Activity not started等错误信息,则需要进一步检查配置 。

链接被浏览器拦截

  • 原因 :未在 Intent Filter 中声明BROWSABLE类别,浏览器无法识别该链接可以被应用处理,从而将其拦截 。

  • 解决方案 :在AndroidManifest.xml中为处理链接的 Activity 添加<category android:name="android.intent.category.BROWSABLE" />,确保浏览器能够将链接正确地传递给应用 。例如:

xml 复制代码
<activity android:name=".DeepLinkActivity"
          android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="deeplink"
            android:scheme="myapp" />
    </intent-filter>
</activity>
  • 原因 :通常是assetlinks.json文件配置错误,如文件路径不正确、内容格式有误、SHA-256 指纹与应用签名证书不匹配等 。例如,在生成assetlinks.json文件时,使用了错误的应用签名证书来获取 SHA-256 指纹,导致验证失败 。

  • 解决方案 :使用adb shell am verify-app-links命令检查验证状态,根据提示信息进行排查 。确保assetlinks.json文件放置在正确的服务器路径下,如https://example.com/.well-known/assetlinks.json;仔细检查文件内容,确保package_namesha256_cert_fingerprints与应用实际情况一致 。如果指纹不匹配,需要重新获取正确的 SHA-256 指纹并更新assetlinks.json文件 。获取 SHA-256 指纹的方法可以参考前文提到的使用命令行工具或 Android Studio 的方式 。

多个应用注册相同 scheme 冲突

  • 原因 :当多个应用声明了相同的自定义 Scheme 时,系统无法确定应该使用哪个应用来打开链接,从而导致冲突 。例如,两个不同的新闻类 App 都注册了news://的 Scheme,用户点击news://article/123链接时,系统会弹出选择器询问用户使用哪个应用打开,这不仅影响用户体验,还可能导致用户误操作 。

  • 解决方案:优先使用 App Link(HTTPS),因为 App Link 通过域名所有权验证,可以避免多个应用注册相同 scheme 的冲突问题 。如果必须使用自定义 Scheme,尽量使用独特的、不易与其他应用冲突的 Scheme,并且在应用中做好提示和引导,告知用户可能出现的选择器情况,并提供清晰的操作指引 。

相关推荐
for_syq2 小时前
trace抓取工具
android·python
黄林晴2 小时前
Compose Multiplatform 1.10 发布:统一 Preview、Navigation 3、Hot Reload 三箭齐发
android·flutter
Kapaseker2 小时前
一杯 Kotlin 美式品味 object 声明
android·kotlin
常利兵2 小时前
Room 3.0大变身:安卓开发的新挑战与机遇
android·jvm·oracle
阿拉斯攀登2 小时前
【RK3576 安卓 JNI/NDK 系列 09】RK3576 实战(三):JNI 调用 librga 实现 2D 硬件加速图像处理
android·驱动开发·rk3568·瑞芯微·rk安卓驱动·rk3576 rga加速
落羽的落羽3 小时前
【Linux系统】信号机制拆解,透过内核三张表深入本质
android·java·linux·服务器·c++·spring·机器学习
峥嵘life3 小时前
Android16 EDLA【GTS】GtsPermissionTestCases存在fail项
android·学习
魑魅魍魉都是鬼3 小时前
Android:java kotlin 单例模式
android·java·单例模式
段娇娇11 小时前
Android jetpack LiveData(一)使用篇
android·android jetpack