主頁 > 移動端開發 > Android組件化開發簡單示例

Android組件化開發簡單示例

2020-11-22 12:16:23 移動端開發

Android組件化示例代碼github地址:https://github.com/respost/ModuleDemo

一、組件化初始模型

1、通過一個簡單的android專案初始架構圖來了解組件化,如下圖:

打個生動的比喻,把我們的APP當成一個電腦主機,那么app外殼就是主機外殼,main組件就是主板,其他各個組件就類似于硬碟、網卡、顯卡之類的東西,各個組件連接到主板上,然后再安裝到主機殼中,對外展示為一個完整的電腦主機,

2、app外殼和main組件是我們app的必備組成部分,一起構成了可對外發布的完整app,其他組件可以集成進來,也可以不集成進來,只會增加或者減少我們app的功能,但不影響我們app的最終發布,

二、創建Module模塊(組件)

在我們的實際專案中,組件展示出來的效果大概是這樣的:

1、我們開始創建Module模塊,專案的APP上右鍵 → New → Module

2、選擇 Android Library → Next

3、 輸入模塊名稱 → Finish

三、組件的build.gradle檔案說明

1、通過以上Module模塊的創建,包括main組件在內,一共有5個組件,所以對應的有5個組件build.gradle檔案,如下圖:

2、 main組件的gradle檔案中,apply plugin使用的是com.android.application

3、其他業務模塊(組件A、組件B、組件C、common組件等),apply plugin使用的是com.android.library

四、組件集成

各個組件都建立完成之后,接下來可以把組件集成到main組件中,集成非常簡單,只需在main組件的gradle檔案中添加dependencies{}配置,添加如下陳述句:

dependencies {
     ...

    //集成組件A
    implementation project(':modulea')
    //集成組件B
    implementation project(':moduleb')
    //集成組件C
    implementation project(':modulec')
}

如下圖:

五、組件資源共享

1、在common組件的build.gradle檔案中,添加android 配置,如下:

android {

    //省略前面的代碼...

    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}

在各個需要呼叫公共common組件的組件build.gradle檔案中,也添加android 配置,如下:

android {
   
     //省略前面的代碼..

    repositories {
        flatDir {
            dirs '../common/libs/', 'libs'
        }
    }

}

2、common組件里引入各種類別庫的時候必須用api,而不是用implementation,原因:

implementation編譯的依賴只作用于當前的module,即common組件模塊中使用implementation編譯的三方庫只對common模塊起作用,main組件模塊中無法使用該三方庫,

3、關于組件資源共享,舉個簡單示例:例如圖片都是存放到公共的common組件的res里,那么如何在組件A、組件B、組件C里使用呢?

使用方法如下:

  • 打開各組件的build.gradle檔案,在dependencies{}里添加如下代碼即可:
dependencies {
    
    ...

    implementation project(':common')
}
  • 如此一來,就能在組件A里呼叫common組件的圖片資源了

4、同樣的道理, 組件A、 組件B、 組件C的顏色代碼也可以直接呼叫公共common組件里colors.xml的代碼

5、我們可以把其他第三方庫、自定義view、工具類、公用資源都放進公共common組件里,也就是說組件A、組件B、組件C里build.gradle所引入的類別庫,都可以放到common組件里的dependencies{}里

6、所以各個業務組件里面的build.gradle檔案的dependencies{}配置簡化后,就變成了下面這樣:

7、通過以上解說,大家應該都明白了吧,圖片、xml這些(value目錄下的各種xml檔案),都可以放到公共common組件里,然后再被其他組件參考,對于全域共用的style.xml檔案,我們更應該把它放在common組件中,例如我們的專案theme,本來是放在main組件的style里面,我們可以把它移到common中,這樣其他組件除錯時,作為一個單獨的專案,也能和主專案有一樣的主題,總而言之,所有你認為可以被各個組件共享的資源,都可以放在common組件中,

六、往組件里添加Fragment

1、以組件A為例,在組件A里添加一個包fragment

2、在fragment包右鍵 → New → Fragment →Fragment(Blank)

3、 填寫Fragment碎片名稱,勾選創建xml檔案,如下:

4、對應的fragment_module_a.xml檔案代碼:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/a" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="5dp"
        android:text="組件A"
        android:background="@color/green"
        android:textColor="@android:color/white"
        android:textSize="24dp" />

</FrameLayout>

5、其他組件也類似組件A一樣,創建一個Fragment碎片,然后添加不同的背景圖片即可,

6、main組件里添加導航和Fragment容器,main組件里activity_main.xml的代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </FrameLayout>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/navigation" />
</LinearLayout>

7、res下創建一個menu目錄,里面添加一個navigation.xml檔案,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/navigation_a"
        android:icon="@drawable/home"
        android:title="組件A" />
    <item
        android:id="@+id/navigation_b"
        android:icon="@drawable/video"
        android:title="組件B" />
    <item
        android:id="@+id/navigation_c"
        android:icon="@drawable/me"
        android:title="組件C" />
</menu>

navigation.xml里呼叫的icon圖片分別放到drawable和drawable-24目錄里,最終主APP的MainActivity界面如下圖:

8、MainActivity.java的代碼如下:

package net.zy13.module.demo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;

import android.os.Bundle;
import android.view.MenuItem;

import com.google.android.material.bottomnavigation.BottomNavigationView;

import net.zy13.module.modulea.fragment.ModuleAFragment;
import net.zy13.module.moduleb.fragment.ModuleBFragment;
import net.zy13.module.modulec.fragment.ModuleCFragment;

public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {

    //定義碎片集合
    private Fragment[] fragments = new Fragment[3];
    //當前顯示的fragment的索引位置
    private int currentIndex = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFragment();
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(this);
    }

    /**
     * 初始化Fragment碎片
     */
    private void initFragment() {
        if (fragments[0] == null) {
            fragments[0] = new ModuleAFragment();
            getSupportFragmentManager().beginTransaction().add(R.id.content, fragments[0], "moduleA").commit();
        } else {
            getSupportFragmentManager().beginTransaction().show(fragments[0]);
        }
    }

    /**
     * 導航選擇事件
     * @param item
     * @return
     */
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.navigation_a:
                if (currentIndex == 0) return true;//如果已經是當前的fragment,不用切換
                FragmentTransaction transition0 = getSupportFragmentManager().beginTransaction();
                hideAndShow(0,transition0);
                return true;

            case R.id.navigation_b:
                if (currentIndex == 1) return true;//如果已經是當前的fragment,不用切換
                FragmentTransaction transition1 = getSupportFragmentManager().beginTransaction();
                if (fragments[1] == null) {
                    fragments[1] = new ModuleBFragment();
                    transition1.add(R.id.content, fragments[1], "moduleB");
                }
                hideAndShow(1,transition1);
                return true;

            case R.id.navigation_c:
                if (currentIndex == 2) return true;//如果已經是當前的fragment,不用切換
                FragmentTransaction transition2 = getSupportFragmentManager().beginTransaction();
                if (fragments[2] == null) {
                    fragments[2] = new ModuleCFragment();
                    transition2.add(R.id.content, fragments[2], "modulec");
                }
                hideAndShow(2,transition2);
                return true;
        }
        return false;
    }

    /**
     * 除了指定的fragment不hide,其他fragment全hide
     * @param expectIndex 指定的fragment在fragments中的位置
     * @param transition
     */
    private void hideAndShow(int expectIndex,FragmentTransaction transition) {
        for (int i = 0; i < fragments.length; i++) {
            if (i != expectIndex && fragments[i] != null) {
                transition.hide(fragments[i]);
            }
        }
        transition.show(fragments[expectIndex]);
        transition.commit();
        currentIndex = expectIndex;
    }
}

9、Run運行專案,最終效果如下圖,點擊導航,可以切換到對應的組件上:

七、各個組件單獨開發(測驗)

前面我們把各個組件集成到main組件中,現在我們把組件拆分出來,單獨開發,開發測驗完成后,再把組件集成到main組件中,最后發布,組件單獨出來開發的方法就是:在build.gradle檔案中,把apply plugin: 'com.android.library',改成apply plugin: 'com.android.application',也就是把其library模式改為application模式,因為只有application才可以單獨運行,library必須依靠application才能運行,

那么問題來了?

組件單獨開發時,我們需要改build.gradle的apply plugin模式,等要集成到main組件時,又得改回來,如果這樣子手工去改,組件一多,修改起來比較麻煩,也不優雅,優雅的解決辦法就是設定一個開關,打開時,就是application模式,可以單獨開發;關閉時,就是library模式,可以集成到main組件中,現在按我下面的步驟來實作:

1、在專案根目錄下,有一個build.gradle檔案,在這個檔案最末尾添加一個ext {}配置,然后在ext配置里設定一個常量isDebug,值設為true

ext {
    /**
     * 組件除錯模式
     * isDebug = true 是組件模塊,說明是單獨的App
     * isDebug = false是集成模式,說明是依賴Lib
     * 每次更改“isDebug”的值后,需要點擊 "Sync Project" 按鈕
     *
     */
    isDebug = true
}

2、build.gradle里設定了isDebug常量后,我們專案中的其他build.gradle檔案都可以把這個常量讀取出來,所以我們可以在其他組件的build.gradle檔案中,讀取該常量的值,動態設定apply plugin,代碼如下:

if(isDebug){
    apply plugin: 'com.android.application'
}else{
    apply plugin: 'com.android.library'
}

3、這樣子設定之后,當我們需要切換模式時,只需要修改專案根目錄下build.gradle檔案中isDebug常量的值,修改完成之后,點擊Project sync按鈕同步一下即可,如果有報錯,那么還有個地方需要修改一下,就是main組件的build.gradle檔案,我們把module的模式改成了application,main組件就不能引入application,引入的話就會報錯,所以當是debug除錯模式時,這里就不引入該組件,以免報錯,所以在集成組件前,要先判斷是什么模式,如下圖:

4、接下來還得修改 AndroidManifest.xml,當把一個module設定為application時,AndroidManifest.xml需要包含一個app所需要的屬性,例如app的icon、theme、launch Activity這些屬性設定,而當module為library時,這些屬性就都不需要用到,所以當我們處于不同模式時,AndroidManifest.xml檔案的配置也得不同,方法如下:

(1)、Android目錄模式切換到Project目錄模式

(2)、 在各個組件的src檔案夾中新創建一個debug目錄,再把我們用于debug除錯的AndroidManifest.xml檔案放進去

(3)、除錯用的AndroidManifest.xml檔案可以直接復制manifests目錄里的,然后添加application的基本資訊,如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.zy13.module.modulea">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    </application>
</manifest>

以上內容會有很多錯誤提示,其實提示的無非就是資源找不到,既然前面我們已經創建了公共的common組件,那么我們只需要把main組件中相應的資源移動到common組件中就可以了,

5、接下來在各個組件的build.gradle檔案中,指定不同模式下使用的AndroidManifest.xml檔案,在android {}里添加如下代碼:

sourceSets {
        main {
            if (isDebug) {
                manifest.srcFile 'src/debug/AndroidManifest.xml'
            }else{
                manifest.srcFile 'src/main/AndroidManifest.xml'
                //集成開發模式下排除debug檔案夾中的所有Java檔案
                java {
                    exclude 'debug/**'
                }
            }
        }
}

6、以上設定完成,并且sync project(同步專案)之后,各個組件會是這樣的目錄結構:

7、在各個組件里創建一個用于除錯啟動的MainActivity活動,然后把fragment加載到activity_main.xml里,所對應的activity_main.xml布局檔案如下:

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="net.zy13.module.modulea.fragment.ModuleAFragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>

8、添加MainActivity活動后,我們還需要手動設定該活動為入口,打開src/debug/目錄下的AndroidManifest.xml檔案,修改MainActivity的配置如下:

<activity
    android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

9、以上步驟完成之后,組件就可以單獨作為一個app來開發測驗了,android studio的運行app里面,同時多了幾個可運行的專案,如下圖:

八、統一專案版本號

各個組件的build.gradle檔案中,有很多版本號,為了避免每次修改都得同時修改多份build.gradle檔案,也避免不同的組件使用的版本不一樣,導致沖突,所以我們可以把這些版本號統一管理起來,方法如下:

1、在專案根目錄下的build.gradle檔案中,定義版本號常量

ext {
    /**
     * 組件除錯模式
     * isDebug = true 是組件模塊,說明是單獨的App
     * isDebug = false是集成模式,說明是依賴Lib
     * 每次更改“isDebug”的值后,需要點擊 "Sync Project" 按鈕
     *
     */
    isDebug = true
    //版本號
    android = [
            compileSdkVersion: 30,
            buildToolsVersion: "30.0.0",
            minSdkVersion    : 15,
            targetSdkVersion : 30,
            versionCode      : 1,
            versionName      : "1.0"
    ]
}

2、然后在各個組件的build.gradle檔案中,做這樣的修改:

android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion
    defaultConfig {
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
    }
}

九、使用路由實作組件之間的通信

通過前面的學習,我們已經知道組件可以拆分了,但是當他們集成到main組件中時,還是需要一定的通信,例如業務A需要呼叫到業務B的一個頁面,甚至進行傳參,但是在“組件化”模式下,業務A和業務B是完全分開的,在業務A的認知里,根本就不存在業務B,也就沒辦法直接呼叫,當然,如果要業務A與業務B可以直接通信,互相引入就可以,但是這樣的話,專案耦合性太高,架構也混亂,會把“組件化”的所有優點都一一撇掉,所以我們應該用另外一種方式來處理,

這里需要引入一個概念:路由”,就如我們實際訪問網路一樣,我們電腦發送的請求都經過路由器轉發,在“組件化”中,我們也可以設定這么一個中轉站,來統一處理不同組件之間的呼叫關系,關于路由的用法,后面會補充,這里先用最簡單的方法,來實作組件之間的呼叫(頁面跳轉),代碼如下:

try {
    Class c= Class.forName("net.zy13.module.modulea.MainActivity");
    Intent intent = new Intent(context,c);
    startActivity(intent);
} catch (ClassNotFoundException e) {
    Log.e("組件","組件未集成,無法跳轉");
}

以上代碼是通過完整的類名來進行跳轉,在debug模式下,呼叫其他組件時,找不到對應組件,不會直接報錯,只是提示“未集成,無法跳轉”,我們可以把這個方法寫成一個工具類,放在common組件中,方法如下:

1、在common組件里創建一個工具類PageUtils.java,代碼如下:

import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * @author 安陽 QQ:15577969
 * @version 1.0
 * @team 美奇軟體開發作業室
 * @date 2020/11/12 11:55
 */
public class PageUtils {
    /**
     * 頁面跳轉
     * @param context
     * @param className
     */
    public static void jump(Context context, String className){
        try {
            Class c = Class.forName(className);
            Intent intent = new Intent(context,c);
            context.startActivity(intent);
        } catch (ClassNotFoundException e) {
            Log.e("組件","未集成,無法跳轉");
        }
    }

    /**
     * 頁面跳轉,可以傳參,引數放在intent中,所以需要傳入一個intent
     * @param context
     * @param className
     * @param intent
     */
    public static void jump(Context context,String className,Intent intent){
        try {
            Class c = Class.forName(className);
            intent.setClass(context,c);
            context.startActivity(intent);
        } catch (ClassNotFoundException e) {
            Log.e("組件","未集成,無法跳轉");
        }
    }
}

2、在需要跳轉的地方,直接用以下方法呼叫:

PageUtils.jump(context,"net.zy13.module.modulea.MainActivity");

還有一種通信情況,就是其中某個組件的改變會影響到其他組件的改變,例如用戶的登陸情況(是否登錄),會影響到其他組件中一些控制元件的顯示情況,這個時候我們可以用android的廣播機制,或者用EventBus來解決,實際開發中,如果是像這種會影響全域的改變,應該放在公共的common組件之中,用戶的登陸情況,是影響全域的存在,那么就可以在common中,定義一個用戶單例,其他組件分別拿這個單例去控制其界面的顯示,特別是引入databingding之后,操作起來更為方便,具體的實作方式大家可以百度參考其他教程,這里我就不實作了,

十、android路由框架

關于路由框架的具體用法,我單獨整理成了一篇文章,示例代碼也是寫在了組件化專案里,

Android的路由框架用法:https://blog.csdn.net/qq15577969/article/details/109690111

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/226263.html

標籤:其他

上一篇:Activity的四種啟動模式

下一篇:Android實作ListView下拉重繪思路以及流程

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more