主頁 > 移動端開發 > Gradle 自定義插件

Gradle 自定義插件

2020-09-16 05:10:09 移動端開發

思維導圖

使用版本 5.6.2

插件被用來封裝構建邏輯和一些通用配置,將可重復使用的構建邏輯和默認約定封裝到插件里,以便于其他專案使用,

你可以使用你喜歡的語言開發插件,但是最終是要編譯成位元組碼在 JVM 運行的,

Gradle 有兩種插件,腳本插件和二進制插件,

關于插件的介紹,可以參考我的另一篇文章 Gradle 插件

這里講的自定義插件是二進制插件,二進制插件可以打包發布,有利于分享,

可以在三個地方定義插件

  • 在腳本里
  • 在 buildSrc 下
  • 在單獨的專案里

三個地方的插件的用途目的不同,

在腳本里的插件

其他專案無法使用,只能在本腳本里使用,

在 buildSrc 下

在專案的 buildSrc 目錄下的插件,這個專案里的所有(子)專案都可以使用,

在單獨的專案里

你可以為你的插件創建一個專案,這個專案可以打包發布 JAR,提供給其他任何專案使用,

創建一個插件

建議使用靜態語言,例如 Java ,Kotlin,開發工具建議使用 IntelliJ IDEA ,

一個插件就是個實作了 Plugin 的類,

當插件被應用到專案時,Gradle 會實體化這個插件并呼叫 Plugin.apply() 方法,并將這個專案的實體當做引數傳遞進去,插件就可以對這個專案進行各種配置了,

CustomPLugin.java

// 定義一個插件
class CustomPLugin implements Plugin<Project>{

    @Override
    void apply(Project target) {
        // do something
    }
}

前面說到可以在三個地方創建插件,現在來一一實作下,

在腳本里創建一個插件

可以在 build.gradle 腳本里任意地方定義,

build.gradle

// 定義一個插件
class CustomPLugin implements Plugin<Project>{

    @Override
    void apply(Project target) {
      //添加一個任務
     target.task('hello', group: 'util') {
         doLast {
             logger.quiet("Hello Plugin.")
         }
     }
    }
}

//直接在腳本里應用
apply plugin:CustomPLugin

在 gradle 視窗就可以看到應用插件后的添加的任務
添加的任務

雙擊任務或者命令列輸入都可以執行 hello 任務

gradle hello

在專案的 buildSrc 目錄下創建專案

這里使用的是 Groovy ,

在這個目錄下創建專案會被 Gradle 自動識別的,

結構如下

buildSrc 目錄結構

  1. 在專案根目錄下創建目錄 buildSrc
  2. 在 buildSrc 下按照 java 工程或者 groovy 工程(這取決于你用什么語言)新建目錄

$projectDir/buildSrc/src/main/groovy

  1. 在 groovy 創建你的包 (可能現在還不能被識別為專案,那就創建目錄),例如 com.github.skymxc
  2. 在包里創建插件,也就是創建一個實作了 Plugin 的類,

這里做簡單的示范:

在插件里為 jar 任務添加一個操作:生成記錄檔案

JarLogPlugin.groovy

/**
 * 輸出 生成記錄到指定檔案
 */
class JarLogPlugin implements Plugin<Project> {
    @Override
    void apply(Project target) {
        //增加一個擴展配置用來接收引數
        target.extensions.create("log", LogExtension)

        //添加一個任務
        target.task(type: Jar,group:'util','jarWithLog',{
            doLast {
                //使用配置
                def file = target.log.outputPath;
                if (file==null){
                    file = new File(target.projectDir,"/log/jarlog.txt").getPath()
                }
                println "存盤目錄是 ${file}"
                def content = "${getArchiveFileName().get()}---${getNow()}\n"
                writeFile(file,content)
            }
        })

        //為 jar 任務添加一個 操作,
        target.tasks.jar.doLast {
            println "當前時間是 ${getNow()},打了一個 jar-> ${version}"
            //存到指定檔案記錄
            def file = new File(target.projectDir,"/log/jarlog.txt");
            def content = "${version}---${getNow()}\n"
            writeFile(file.getAbsolutePath(),content)
        }
    }

    def String getNow(){
        def dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss.SSS");
        return dateFormat.format(Calendar.getInstance().getTime());
    }

    def void writeFile(String path,String content){
        def file = new File(path);
        if (!file.exists()){
            if (!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
        }
        FileWriter writer = new FileWriter(file.getAbsolutePath(),true);
        BufferedWriter bufferedWriter = new BufferedWriter(writer);
        bufferedWriter.write(content);
        bufferedWriter.close();
    }
}

配置 DSL

上面使用了一個擴展來接收引數, 普通的物件就可以,例如

LogExtension.groovy

class LogExtension {
    String outputPath;
}

擴展在這里就是用來為插件配置 DSL 用的,

//為 專案添加了一個 LogExtension 型別的屬性 名字是 log
project.extensions.create("log", LogExtension)

插件可以使用 DSL 接收引數,在插件或者任務里直接通過 Project 實體訪問即可,

def file = project.log.outputPath;

插件創建完成后,在專案的里就可以使用了,

現在可以使用類名應用插件了,

build.gradle

import com.github.skymxc.JarLogPlugin

apply plugin: JarLogPlugin

插件應用成功后就可以使用 DSL 為插件配置引數,

配置記錄檔案地址:

build.gradle

log {
    outputPath rootProject.projectDir.getPath()+"\\record\\jar.txt"
}

為插件創建 ID

  1. 在 main 目錄下創建 resources 檔案夾
  2. 在 resources 目錄下創建 META-INF 檔案夾
  3. 在 META-INF 目錄下創建 gradle-plugins 檔案夾
  4. 在 gradle-plugins 目錄下創建 properties 檔案,名字就是你的插件 ID,
  5. 在 id.properties 檔案里通過 implementation-class 指向你的實作類,

例如

src / main / resources / META-INF / gradle-plugins / com.github.skymxc.sample.properties

implementation-class= com.github.skymxc.JarLogPlugin

然后就可以使用插件 ID 了

plugins {
    id 'com.github.skymxc.sample'
}

關于插件 id 的規范:

  • 可以包含任何字母數字字符 “ . ”和 “ - ”,
  • 必須至少包含一個 “ . ” ,
  • 一般使用小寫的反向域名,(類似包名)
  • 不能以 “ . ” 結尾,
  • 不能包含連續的 “ . ” ,

關于 Groovy 的語法,可以參考 Groovy 語法,

在單獨的專案里創建插件

這次仍然是使用 Groovy 語言,

這里的插件專案其實就是一個 Groovy 專案,當然了你如果使用 Java 語言就是一個 Java 工程,

創建一個工程

創建出來的專案就是這樣子,標準的 Groovy 工程目錄

創建Groovy工程

更改 build.gradle 腳本,配置專案

  1. 應用 maven-publih 插件
  2. 添加 Gradle 和 Groovy 的依賴
  3. 配置上傳任務

最后就是這樣子

plugins {
    id 'groovy'
    id 'maven-publish'
}

group 'com.github.skymxc'
version '1.0.0'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

//使用 groovy 和 gradle 依賴
dependencies {
    compile gradleApi()
    compile localGroovy()
}
publishing {
    repositories {
        maven {
            name 'local'
            url 'file://E:/libs/localMaven'
        }
    }
    publications {
        maven(MavenPublication) {
            groupId = 'com.github.skymxc'
            artifactId = 'plugin'
            version = '1.0.0'
            from components.java
        }
    }

}

創建兩個插件:

一個是上面創建的那個,就不重復粘貼了,

另一個插件 Greet,配置一個任務,簡單的輸出一句話,

class Greet implements Plugin<Project> {
    @Override
    void apply(Project target) {
        target.extensions.create("hello", Hello)
        target.task("hello") {
            doLast {
                println "message -> ${target.hello.message}"
            }
        }
    }
}

Hello.groovy

class Hello {
    String message
}

插件 ID 的配置是跟上面一樣的,

目錄結構圖

執行 maven-publish 的 publish 任務,將插件發布到指定倉庫,

gradlew -p plugin publish

發布成功后的倉庫

發布成功的圖片

插件創建完成了,也發布了,下面就是使用這個插件了,

這里對插件的使用就簡單介紹一下,詳細的可以查看之前的這篇介紹:Gradle 插件

  1. 在根專案的 build.gradle 配置倉庫,添加依賴
buildscript {
    repositories {
        maven {
            url 'file://E:/libs/localMaven'
        }
    }
    dependencies {
        classpath 'com.github.skymxc:plugin:1.0.2'
    }
}
  1. 應用插件

我分別在兩個 Java 專案里使用了插件:

  • 一個是使用 id 的方式
  • 一個是使用類名的方式

lib_2/ build.gradle 使用 類名的方式

······

apply plugin:'com.github.skymxc.greet'

hello{
    message '使用了 com.github.skymxc.greet 插件'
}

······

lib_1/ build.gradle 使用 id 的方式

plugins {
    id 'java'
    id 'com.github.skymxc.jarlog'
}

······

logConfigure {
    outputPath rootProject.projectDir.getPath()+"\\record\\jar.txt"
}

應用插件后的 gradle 視圖,可以看到已經添加的任務,

gradle 視圖-任務

使用 java-gradle-plugin 開發插件

像上面一樣創建一個專案,不過這次是一個 java 專案,然后應用這個插件,

java-gradle-plugin 可以減少重復代碼,它自動的應用 java 插件,添加 gradleApi() 依賴,

plugins {
    id 'java-gradle-plugin'
}

使用 gradlePlugin {} 配置塊可以配置開發的每一個插件,不用手動創建對應的屬性檔案了,

gradlePlugin {
    plugins {
        greetPlugin {
            id = 'com.github.skymxc.greet'
            implementationClass = 'com.github.skymxc.GreetPlugin'
        }

        jarWithLogPlugin {
            id = 'com.github.skymxc.jar-log'
            implementationClass = 'com.github.skymxc.JarWithLogPlugin'
        }
    }
}

插件會在 jar 檔案里自動生成對應的 META-INF 目錄,

配合 maven-publish 可以為每個插件創建對應的發布任務,

在發布時也會為每個插件發布對應的 “插件標記工件” ,

插件標記工件

關于 插件標記工件這里插一下:

每個 maven 工件都是由三部分標識的

  • groupId
  • artifactId
  • version

平常我們添加依賴的這樣的:

implementation 'groupId:artifactId:version'

而我們的插件是通過 id 應用的,怎么通過 id 找到對應的工件呢,這就有了“插件標記工件”,
應用插件時會把 id 映射成這樣:plugin.id: plugin.id.gradle.plugin:plugin.version

即:

  • plugin.id
  • plugin.id.gradle.plugin
  • plugin.version

舉個上面的例子:com.github.skymxc.greet 插件對應的工件就是:

com.github.skymxc.greet:com.github.skymxc.greet.gradle.plugin:1.0.0

部分代碼:

plugins {
    id 'java-gradle-plugin'
    id 'maven-publish'
}

group 'com.github.skymxc'
version '1.0.0'


gradlePlugin {
    plugins {
        greetPlugin {
            id = 'com.github.skymxc.greet'
            implementationClass = 'com.github.skymxc.GreetPlugin'
        }

        jarWithLogPlugin {
            id = 'com.github.skymxc.jar-log'
            implementationClass = 'com.github.skymxc.JarWithLogPlugin'
        }
    }
}

publishing {
    repositories {
        maven {
            name 'local'
            url 'file://E:/libs/localMaven'
        }
    }
}

maven-publish 的任務

簡單介紹一下 maven-publish 的發布任務

  • generatePomFileFor${PubName}Publication

    為名字為 PubName 的的發布創建一個 POM 檔案,填充已知的元資料,例如專案名稱,專案版本和依賴項,POM檔案的默認位置是build / publications / $ pubName / pom-default.xml,

  • publish${PubName}PublicationTo${RepoName}Repository

    將 PubName 發布 發布到名為 RepoName 的倉庫,
    如果倉庫定義沒有明確的名稱,則 RepoName 默認為 “ Maven”,

  • publish${PubName}PublicationToMavenLocal

    將 PubName 發布以及本地發布的 POM 檔案和其他元資料復制到本地Maven快取中
    (通常為$USER_HOME / .m2 / repository),

  • publish

    依賴于:所有的 publish${PubName}PublicationTo${RepoName}Repository 任務
    將所有定義的發布發布到所有定義的倉庫的聚合任務,不包括復制到本地 Maven 快取的任務,

  • publishToMavenLocal

    依賴于:所有的 publish${PubName}PublicationToMavenLocal 任務

    將所有定義的發布(包括它們的元資料(POM檔案等))復制到本地Maven快取,

這張圖列出了為每個插件生成的對應的任務,
插件對應的發布任務

執行發布任務 publish 后可以在對應的倉庫查看

發布后的倉庫圖1
發布后的倉庫圖2

發布插件后的使用

  1. 配置倉庫,這次在 settings.gradle 里配置
pluginManagement {
    repositories {
        maven {
            url 'file://E:/libs/localMaven'
        }
    }
}
  1. 使用插件
plugins {
    id 'java'
    id 'com.github.skymxc.greet' version '1.0.13'
    id 'com.github.skymxc.jar-log' version '1.0.0'
}

應用插件后就可以在 Gradle 的視窗看到對應的任務了,

然后可以根據需要配置 DSL ,

為插件配置 DSL

和插件的互動就是通過 DSL 配置塊進行的,

那怎么為插件配置 DSL 呢,答案是隨便一個普通類都可以的,

通過 Gradle 的 API 可以將一個普通的類添加為 Project 的擴展,即 Project 的屬性,

舉個例子,插件里的任務需要兩個引數:檔案地址,檔案名字,就要通過 DSL 配置的方式解決,

JarLogExtension.java 一個普通的類,有兩個屬性,分別是 name , path

package com.github.skymxc.extension;

public class JarLogExtension {
    private String name;
    private String path;

    //省略 setter/getter
}

在插件里將這個類添加為專案的擴展,

public class JarWithLogPlugin implements Plugin<Project> {

    @Override
    public void apply(Project target) {
        //添加擴展
        target.getExtensions().add("jarLog", JarLogExtension.class);
        //創建任務
        target.getTasks().create("jarWithLog", JarWithLogTask.class);
    }
}

應用插件后就可以在腳本里使用這個 DSL 配置了,

build.gradle

······

/**
 * 為 jarWithLog 配置的 DSL
 */
jarLog {
    path getBuildDir().path+"/libs"
    name "record.txt"
}

······

接下來就是在插件或者任務里獲取 DSL 配置的引數了,

可以通過名字或者型別獲取到這個擴展物件,

public class JarWithLogTask extends Jar {

    @TaskAction
    private void writeLog() throws IOException {
      //獲取到配置
        JarLogExtension extension = getProject().getExtensions().getByType(JarLogExtension.class);

        File file = new File(extension.getPath(),extension.getName());
        String s = file.getAbsolutePath();
        String content = getNow()+" --- "+getArchiveFileName().get();
        System.out.println("path --> "+s);
        writeFile(s,content);
    }
}

嵌套 DSL

在我們日常的使用中,嵌套 DSL 很常見,那怎么實作的呢,

hello {
    message '使用 pluginManagement 管理插件'
    user {
        name 'mxc'
        age 18
    }
}

現在我來實作下:

首先是創建里面的嵌套物件,需要注意的是要為 DSL 配置對應的方法,

UserData.java

package com.github.skymxc.extension;

/**
 * 為了實踐嵌套 DSL 建的
 */
public class UserData {
    private String name;
    private int age;
    public String getName() {
        return name;
    }

    /**
     * 注意此方法 沒有 set
     * @param name
     */
    public void name(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void age(int age) {
        this.age = age;
    }

}

然后是外層的 DSL 對應的類,因為有 DSL 嵌套,所以要使用閉包

package com.github.skymxc.extension;

import org.gradle.api.Action;

/**
 * 為 HelloTask 創建的擴展,用于接收配置引數
 */
public class HelloExtension {

    private String message;
    private final UserData user = new UserData();


    /**
     * 注意此方法沒有 set
     * @param action
     */
    public void user(Action<? super UserData> action) {
        action.execute(user);
    }

    // 省略其他 getter/setter
}

最后就是添加到專案的擴展了,和前面一樣

public class GreetPlugin implements Plugin<Project> {
    @Override
    public void apply(Project target) {
        target.getExtensions().create("hello", HelloExtension.class);
        target.getTasks().create("hello", HelloTask.class);
    }
}

在任務中的獲取也是一樣的

HelloExtension hello = getProject().getExtensions().getByType(HelloExtension.class);
UserData user = hello.getUser();

集合物件

再看一個 DSL 配置,這種集合嵌套也經常見到,下面也來簡單實作一下,

fruits {
    apple {
        color '紅色'
    }

    grape {
        color '紫紅色'
    }

    banana {
        color '黃色'
    }

    orange {
        color '屎黃色'
    }

}

這種配置是配合 NamedDomainObjectContainer 實作的,它接收一個類,這個類必須有一個包含 name 引數的構造方法,

Fruit.java

/**
 * 必須有一個 name 屬性,并且有一個 name 引數的建構式
 */
public class Fruit {

    private String name;
    private String color;

    public Fruit(String name) {
        this.name = name;
    }

    public void color(String color){
        setColor(color);
    }

    //省略 setter/getter
}

配置一個 Factory

FruitFactory.java

import org.gradle.api.NamedDomainObjectFactory;
import org.gradle.internal.reflect.Instantiator;

public class FruitFactory implements NamedDomainObjectFactory<Fruit> {

    private Instantiator instantiator;

    public FruitFactory(Instantiator instantiator) {
        this.instantiator = instantiator;
    }

    @Override
    public Fruit create(String name) {
        return instantiator.newInstance(Fruit.class, name);
    }
}

接著就是創建 NamedDomainObjectContainer 物件并添加到 Project ,

GreetPlugin.java

public class GreetPlugin implements Plugin<Project> {
    @Override
    public void apply(Project target) {

        Instantiator instantiator = ((DefaultGradle)target.getGradle()).getServices().get(Instantiator.class);

        NamedDomainObjectContainer<Fruit> fruits = target.container(Fruit.class,new FruitFactory(instantiator));

        target.getExtensions().add("fruits",fruits);

        target.getTasks().create("printlnFruits", ShowFruitTask.class);
    }
}

現在應用這個插件就可以在腳本里使用上述的 DSL 配置了,

最后是 DSL 配置的接收了

public class ShowFruitTask extends DefaultTask {

    @TaskAction
    public void show(){
        NamedDomainObjectContainer<Fruit> fruits = (NamedDomainObjectContainer<Fruit>) getProject().getExtensions().getByName("fruits");

        fruits.forEach(fruit -> {
            String format = String.format("name: %s , color: %s", fruit.getName(), fruit.getColor());
            getLogger().quiet("fruit : {}",format);
        });
    }
}

關于自定義插件的相關介紹就這些了,更詳細的檔案可以查看 Gradle 用戶手冊

這篇文章的原始碼已經放在 github 上:GradlePractice

資料

  • 自定義插件 https://docs.gradle.org/current/userguide/custom_plugins.html
  • 開發輔助插件 https://docs.gradle.org/current/userguide/java_gradle_plugin.html
  • 使用插件 https://docs.gradle.org/current/userguide/plugins.html
  • 發布 https://docs.gradle.org/current/userguide/publishing_overview.html
  • maven 發布插件 https://docs.gradle.org/current/userguide/publishing_maven.html
  • Gradle 教程 https://gradle.org/guides/?q=Plugin Development
  • Gradle DSL https://blog.csdn.net/zlcjssds/article/details/79229209

End

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

標籤:Android

上一篇:More than one file was found with OS independent path 'lib/armeabi-v7a/libgnustl_shared.so'

下一篇:“無處不在” 的系統核心服務 —— ActivityManagerService 啟動流程決議

標籤雲
其他(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