Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单

简介: Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单

在Android系统中,状态栏(StatusBar)、导航栏(NavigationBar)和下拉菜单(ExPlan)是三个常见的用户界面元素,它们分别提供了一些基本的信息显示和交互功能。例如,状态栏可以显示时间、电量、信号等信息,导航栏可以提供返回、主页、多任务等按钮,下拉菜单可以提供快速设置、通知等选项。并不是所有客户的Android设备都需要或支持这些,有时候客户可能想要自由地控制它们的显示和隐藏。

本文将介绍如何在Android系统中定制添加状态栏、导航栏和下拉菜单的控制功能,以便客户可以根据需求使用。

实现步骤

要实现状态栏、导航栏和下拉菜单的控制功能,需要修改以下几个部分:

  • SystemUI模块:这是一个系统应用程序,负责显示和管理状态栏、导航栏和下拉菜单等界面元素。
  • Settings模块:这是一个系统应用程序,负责提供各种系统设置选项,包括显示设置。
  • 系统属性:这是一种用于存储和传递系统配置信息的机制,可以通过命令行或代码来读写。
  • 广播:这是一种用于在不同组件之间传递消息的机制,可以通过命令行或代码来发送和接收。

需要完成以下几个步骤:

  1. 在SystemUI模块中添加广播接收器,用于接收控制状态栏、导航栏和下拉菜单显示和隐藏的广播,并执行相应的操作。
  2. 在SystemUI模块中添加系统属性读取,用于获取状态栏、导航栏和下拉菜单的初始状态,并创建或移除相应的界面元素。
  3. 在Settings模块中添加开关偏好项,用于控制状态栏、导航栏和下拉菜单的开启和关闭,并发送相应的广播,并写入相应的系统属性。
  4. 编译并运行修改后的系统,并在设置中测试控制功能。

修改示例

SystemUI模块

frameworks/base/packages/SystemUI/AndroidManifest.xml

在SystemUI模块的AndroidManifest.xml文件中 需要添加以下几行代码,用于声明要接收的广播:

<protected-broadcast android:name="sys.explan.show" />
    <protected-broadcast android:name="sys.explan.hide" />
    
    <protected-broadcast android:name="sys.statusbar.show" />
    <protected-broadcast android:name="sys.statusbar.hide" />
    <protected-broadcast android:name="sys.navigationbar.show" />
    <protected-broadcast android:name="sys.navigationbar.hide" />
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java

在SystemUI模块的NavigationBarController.java文件中需要添加一个函数,用于移除所有的导航栏:

public void removeNavigationBars() {
        Display[] displays = mDisplayManager.getDisplays();
        for (Display display : displays) {
            removeNavigationBar(display.getDisplayId());
        }
    }
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java

在SystemUI模块的PhoneStatusBarView.java文件中需要修改,用于根据系统属性来决定是否响应下拉菜单的触摸事件:

(这个文件如果用于动态控制 有bug,除了这个文件其他都正常修改 )

-        return barConsumedEvent || super.onTouchEvent(event);
+       /* String value = SystemProperties.get("persist.sys.explan.enable", "false");
+        if(value.equals("true")){
+          return barConsumedEvent || super.onTouchEvent(event);
+        }else{
+          return true;  
+        }*/
+        //
+          return barConsumedEvent || super.onTouchEvent(event);
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

在SystemUI模块的StatusBar.java文件中,我们需要添加以下几行代码,用于声明和初始化一些变量和方法:

+     private static final String ACTION_HIDE_EXPLAN = "sys.explan.hide";
+     private static final String ACTION_SHOW_EXPLAN = "sys.explan.show";
+     private static final String ACTION_HIDE_STATUS_BAR = "sys.statusbar.hide";
+     private static final String ACTION_SHOW_STATUS_BAR = "sys.statusbar.show";
+     private static final String ACTION_HIDE_NAVIGATION_BAR = "sys.navigationbar.hide";
+     private static final String ACTION_SHOW_NAVIGATION_BAR = "sys.navigationbar.show";
+     private static final String SYS_PROPERTY_STATUS_BAR = "persist.sys.statusbar.enable";
+     private static final String SYS_PROPERTY_NAVIGATION_BAR = "persist.sys.navigationbar.enable";
+     private static final String SYS_PROPERTY_EXPLAN = "persist.sys.explan.enable";
+     protected StatusBarManager mStatusBarManager;
+
      public StatusBar(Context context) {
          super(context);
          ...
+         mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
          ...
      }
+
+  public void explan_show() {
+        mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
+   }
+   public void explan_hide() {
+        mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
+   }

在SystemUI模块的StatusBar.java文件中,还需要修改以下几行代码,用于根据系统属性来决定初始化是否创建或隐藏状态栏、导航栏和下拉菜单:

-        createAndAddWindows(result);
-
+        //ln28_add_start
+        if (!SystemProperties.getBoolean(SYS_PROPERTY_STATUS_BAR, false)) {
+            mStatusBarWindowController.setBarVisibility(View.GONE);
+        }
+        //ln28_add_end
         if (mWallpaperSupported) {
             ...
         }
-
-        createNavigationBar(result);
-
+        //ln28_add_start
+        if (SystemProperties.getBoolean(SYS_PROPERTY_NAVIGATION_BAR, false)) {
+            createNavigationBar(result);
+        }
+        if (SystemProperties.getBoolean(SYS_PROPERTY_EXPLAN, false)) {
+            explan_show();
+        }
+        //ln28_add_end
         if (ENABLE_LOCKSCREEN_WALLPAPER && mWallpaperSupported) {
             ...
         }

在SystemUI模块的StatusBar.java文件中,还还需要添加以下几行代码,用于注册和处理我们要接收的广播 实现逻辑动态控制:

filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
+        filter.addAction(ACTION_HIDE_NAVIGATION_BAR);
+        filter.addAction(ACTION_SHOW_NAVIGATION_BAR);
+        filter.addAction(ACTION_HIDE_STATUS_BAR);
+        filter.addAction(ACTION_SHOW_STATUS_BAR);
+        filter.addAction(ACTION_HIDE_EXPLAN);
+        filter.addAction(ACTION_SHOW_EXPLAN);
         mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL);
     }
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                 ...
             } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 ...
             } else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
                 mQSPanel.showDeviceMonitoringDialog();
+            } else if (ACTION_HIDE_NAVIGATION_BAR.equals(action)) {
+                mNavigationBarController.removeNavigationBars();
+                SystemProperties.set(SYS_PROPERTY_NAVIGATION_BAR, "false");
+            } else if (ACTION_SHOW_NAVIGATION_BAR.equals(action)) {
+                createNavigationBar(null);
+                SystemProperties.set(SYS_PROPERTY_NAVIGATION_BAR, "true");
+            } else if (ACTION_HIDE_STATUS_BAR.equals(action)) {
+                mStatusBarWindowController.setBarVisibility(View.GONE);
+                SystemProperties.set(SYS_PROPERTY_STATUS_BAR, "false");
+            } else if (ACTION_SHOW_STATUS_BAR.equals(action)) {
+                mStatusBarWindowController.setBarVisibility(View.VISIBLE);
+                SystemProperties.set(SYS_PROPERTY_STATUS_BAR, "true");
+            } else if (ACTION_HIDE_EXPLAN.equals(action)) {
+                explan_hide();
+                SystemProperties.set(SYS_PROPERTY_EXPLAN, "false");
+            } else if (ACTION_SHOW_EXPLAN.equals(action)) {
+                explan_show();
+                SystemProperties.set(SYS_PROPERTY_EXPLAN, "true");
             }
         }
     };

OK 到这我们就完成了SystemUI模块的修改,是不是很简单? 接下来我们需要修改Settings模块。

Settings模块

packages/apps/Settings/res/values/strings.xml

在Settings模块的strings.xml文件中,需要添加以下几行代码,用于定义我们要显示的开关偏好项的标题:

<string name="ctrl_statusbar">状态栏</string>
    <string name="ctrl_explan">下拉菜单</string>
    <string name="ctrl_navigationbar">导航栏</string>
packages/apps/Settings/res/xml/display_settings.xml

在Settings模块的display_settings.xml文件中,需要添加以下几行代码,用于创建我们要显示的开关偏好项,并指定它们的键值和标题:

<SwitchPreference
       android:key="ctrl_statusbar"
       android:title="@string/ctrl_statusbar"/>
   <SwitchPreference
       android:key="ctrl_navigationbar"
       android:title="@string/ctrl_navigationbar"/>
   <SwitchPreference
       android:key="ctrl_explan"
       android:title="@string/ctrl_explan"/>
packages/apps/Settings/src/com/android/settings/DisplaySettings.java

在Settings模块的DisplaySettings.java文件中,需要添加以下几行代码,用于注册我们要控制的开关偏好项的控制器:

controllers.add(new ThemePreferenceController(context));
        controllers.add(new BrightnessLevelPreferenceController(context, lifecycle));
        controllers.add(new HdmiSettingsPreferenceController(context, KET_HDMI_SETTINGS));
+        controllers.add(new StatusBarPreferenceController(context));
+        controllers.add(new NavigationBarPreferenceController(context));
+        controllers.add(new ExPlanPreferenceController(context));
packages/apps/Settings/src/com/android/settings/display/StatusBarPreferenceController.java

在Settings模块的StatusBarPreferenceController.java文件中,需要添加以下几行代码,用于实现状态栏开关偏好项的控制器,主要负责读取和写入系统属性,以及发送控制广播:

package com.android.settings.display;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import android.content.Intent;
import android.util.Log;
import android.os.SystemProperties;
public class StatusBarPreferenceController extends AbstractPreferenceController implements
        Preference.OnPreferenceChangeListener {
    private static final String TAG = "StatusBarCtrl";
    private static final boolean DEBUG = true;
    private static final String KEY_STATUS_BAR = "ctrl_statusbar";
    private static final String SYS_PROP_STATUS_BAR_ENABLE = "persist.sys.statusbar.enable";
    public static final String ACTION_HIDE_STATUS_BAR = "sys.statusbar.hide";
    public static final String ACTION_SHOW_STATUS_BAR = "sys.statusbar.show";
    public StatusBarPreferenceController(Context context) {
        super(context);
    }
    @Override
    public String getPreferenceKey() {
        return KEY_STATUS_BAR;
    }
    @Override
    public boolean isAvailable() {
        return true;
    }
    @Override
    public void displayPreference(PreferenceScreen screen) {
        if (!isAvailable()) {
            setVisible(screen, KEY_STATUS_BAR, false);
            return;
        }
        final SwitchPreference mStatusBarPreference = screen.findPreference(KEY_STATUS_BAR);
        if (mStatusBarPreference != null) {
            String value = SystemProperties.get(SYS_PROP_STATUS_BAR_ENABLE, "false");
            mStatusBarPreference.setChecked(value.equals("true"));
            mStatusBarPreference.setOnPreferenceChangeListener(this);
        }
    }
    @Override
    public void updateState(Preference preference) {
        String value = SystemProperties.get(SYS_PROP_STATUS_BAR_ENABLE, "false");
        ((SwitchPreference) preference).setChecked(value.equals("true"));
    }
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean value = (Boolean) newValue;
        if (DEBUG) {
            Log.d(TAG, "key value " + value);
        }
        Intent intent = new Intent();
        if (value) {
            intent.setAction(ACTION_SHOW_STATUS_BAR);
        } else {
            intent.setAction(ACTION_HIDE_STATUS_BAR);
        }
        mContext.sendBroadcast(intent);
        return true;
    }
}
packages/apps/Settings/src/com/android/settings/display/NavigationBarPreferenceController.java

在Settings模块的NavigationBarPreferenceController.java文件中,需要添加以下几行代码,用于实现导航栏开关偏好项的控制器,主要负责读取和写入系统属性,以及发送控制广播:

package com.android.settings.display;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import android.content.Intent;
import android.util.Log;
import android.os.SystemProperties;
public class NavigationBarPreferenceController extends AbstractPreferenceController
        implements Preference.OnPreferenceChangeListener {
    private static final String TAG = "NavigationBarCtrl";
    private static final boolean DEBUG = true;
    private static final String KEY_NAVIGATION_BAR = "ctrl_navigationbar";
    private static final String SYS_PROP_NAVIGATION_BAR_ENABLE = "persist.sys.navigationbar.enable"; 
    public static final String ACTION_HIDE_NAVIGATION_BAR = "sys.navigationbar.hide";
    public static final String ACTION_SHOW_NAVIGATION_BAR = "sys.navigationbar.show";
    public NavigationBarPreferenceController(Context context) {
        super(context);
    }
    @Override
    public String getPreferenceKey() {
        return KEY_NAVIGATION_BAR;
    }
    @Override
    public boolean isAvailable() {
        return true;
    }
    @Override
    public void displayPreference(PreferenceScreen screen) {
        if (!isAvailable()) {
            setVisible(screen, KEY_NAVIGATION_BAR, false);
            return;
        }
        final SwitchPreference mNavigationBarPreference = screen.findPreference(KEY_NAVIGATION_BAR);
        if (mNavigationBarPreference != null) {
            String value = SystemProperties.get(SYS_PROP_NAVIGATION_BAR_ENABLE, "false");
            mNavigationBarPreference.setChecked(value.equals("true"));
            mNavigationBarPreference.setOnPreferenceChangeListener(this);
        }
    }
    @Override
    public void updateState(Preference preference) {
        String value = SystemProperties.get(SYS_PROP_NAVIGATION_BAR_ENABLE, "false");
        ((SwitchPreference) preference).setChecked(value.equals("true"));
    }
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean value = (Boolean) newValue;
        if (DEBUG) {
            Log.d(TAG, "key value " + value);
        }
        Intent intent = new Intent();
        if (value) {
            intent.setAction(ACTION_SHOW_NAVIGATION_BAR);
        } else {
            intent.setAction(ACTION_HIDE_NAVIGATION_BAR);
        }
        mContext.sendBroadcast(intent);
        return true;
    }
}
packages/apps/Settings/src/com/android/settings/display/ExPlanPreferenceController.java

在Settings模块的ExPlanPreferenceController.java文件中,需要添加以下几行代码,用于实现下拉菜单开关偏好项的控制器,主要负责读取和写入系统属性,以及发送控制广播:

package com.android.settings.display;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import android.content.Intent;
import android.util.Log;
import android.os.SystemProperties;
public class ExPlanPreferenceController extends AbstractPreferenceController implements
        Preference.OnPreferenceChangeListener {
    private static final String TAG = "ExPlanCtrl";
    private static final boolean DEBUG = true;
    private static final String KEY_EXPLAN = "ctrl_explan";
    private static final String SYS_PROP_EXPLAN_ENABLE = "persist.sys.explan.enable";
    private static final String ACTION_HIDE_EXPLAN = "sys.explan.hide";
    private static final String ACTION_SHOW_EXPLAN = "sys.explan.show";
    public ExPlanPreferenceController(Context context) {
        super(context);
    }
    @Override
    public String getPreferenceKey() {
        return KEY_EXPLAN;
    }
    @Override
    public boolean isAvailable() {
        return true;
    }
    @Override
    public void displayPreference(PreferenceScreen screen) {
        if (!isAvailable()) {
            setVisible(screen, KEY_EXPLAN, false);
            return;
        }
        final SwitchPreference mExPlanPreference = screen.findPreference(KEY_EXPLAN);
        if (mExPlanPreference != null) {
            String value = SystemProperties.get(SYS_PROP_EXPLAN_ENABLE, "false");
            mExPlanPreference.setChecked(value.equals("true"));
            mExPlanPreference.setOnPreferenceChangeListener(this);
        }
    }
    @Override
    public void updateState(Preference preference) {
        String value = SystemProperties.get(SYS_PROP_EXPLAN_ENABLE, "false");
        ((SwitchPreference) preference).setChecked(value.equals("true"));
    }
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean value = (Boolean) newValue;
        if (DEBUG) {
            Log.d(TAG, "key value " + value);
        }
        Intent intent = new Intent();
        if (value) {
            intent.setAction(ACTION_SHOW_EXPLAN);
        } else {
            intent.setAction(ACTION_HIDE_EXPLAN);
        }
        mContext.sendBroadcast(intent);
        
        return true;
    }
}

这样就完成了Settings模块的修改,接下来直接编译并运行修改后的系统,并在设置中测试控制功能。

测试结果

以下是我在模拟器上测试的结果,您可以看到状态栏、导航栏和下拉菜单的显示和隐藏效果:

这是全部关闭的效果

这是全部打开的效果

重启后看到设置保存 到此, 需求实现完毕。

忘记了 如果要设置属性默认值你们自己随便找个位置添加就OK了。

+PRODUCT_PROPERTY_OVERRIDES += persist.sys.statusbar.enable=true
+PRODUCT_PROPERTY_OVERRIDES += persist.sys.navigationbar.enable=true
+PRODUCT_PROPERTY_OVERRIDES += persist.sys.explan.enable=true

结语

本文介绍了如何在Android系统中添加状态栏、导航栏和下拉菜单的控制功能,主要涉及了SystemUI模块和Settings模块的修改,以及系统属性和广播的使用。这些功能可以让用户控制和调用决定是否启用显示xx。

希望本文对你有所帮助,如果有任何问题或建议,请私信和留言。

目录
打赏
0
1
1
0
75
分享
相关文章
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
175 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
134 16
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
android 自定义下拉菜单
    本实例的自定义下拉菜单主要是继承PopupWindow类来实现的弹出窗体,各种布局效果可以根据自己定义设计。弹出的动画效果主要用到了translate、alpha、scale,具体实现步骤如下:          先上效果图如下:左边下拉菜单、中间下拉菜单、右边下拉菜单                   1.主界面布局 activity_main.xml
2659 0
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
50 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
54 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
    13
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    20
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    9
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    5
  • 5
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    7
  • 6
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    3
  • 7
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    10
  • 8
    Android实战经验之Kotlin中快速实现MVI架构
    12
  • 9
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    9
  • 10
    android FragmentManager 删除所有Fragment 重建
    3
  • 1
    android FragmentManager 删除所有Fragment 重建
    20
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    36
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    37
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    43
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    151
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    47
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    64
  • 8
    Android历史版本与APK文件结构
    168
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    51
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    50
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等