Android系统移植与调试之------->如何修改Android手机NFC模块,使黑屏时候能够使用NFC

简介:          我们都知道在不修改源代码的情况下,只能是解锁之后才能使用NFC功能。而在锁屏和黑屏2个状态下是没办法用NFC的,但是最近有个客户要求手机在黑屏状态下能够使用NFC,因此我们需要去修改Android源代码关于NFC模块。

         我们都知道在不修改源代码的情况下,只能是解锁之后才能使用NFC功能。而在锁屏和黑屏2个状态下是没办法用NFC的,但是最近有个客户要求手机在黑屏状态下能够使用NFC,因此我们需要去修改Android源代码关于NFC模块。

       最开始可以通过查看分析源代码,找到到NfcService的相关代码,如下: packages\apps\Nfc\src\com\android\nfc\NfcService.java 


找到186行,这句是定义NFC能够使用的屏幕最小状态

// minimum screen state that enables NFC polling
    static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;

这几个状态分别是:

SCREEN_STATE_OFF黑屏状态   

SCREEN_STATE_ON_LOCKED屏幕亮了,但是是锁屏状态

SCREEN_STATE_ON_UNLOCKED 屏幕亮了,并且是解锁状态

代码定义如下,在packages\apps\Nfc\src\com\android\nfc\ScreenStateHelper中定义

    static final int SCREEN_STATE_UNKNOWN = 0;
    static final int SCREEN_STATE_OFF = 1;
    static final int SCREEN_STATE_ON_LOCKED = 2;
    static final int SCREEN_STATE_ON_UNLOCKED = 3;

上面的这个最小状态在 NfcService.java的第1706行,computeDiscoveryParameters(int screenState)方法中被调用,用来判断的,方法代码如下:

private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
        
        Log.d(TAG, "computeDiscoveryParameters() screenState:"+describeScreenState(screenState));

        if(screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED)
            Log.d(TAG, "!!!! SCREEN_STATE_ON_LOCKED,, mNfcUnlockManager.isLockscreenPollingEnabled():"+mNfcUnlockManager.isLockscreenPollingEnabled());
        
        // Recompute discovery parameters based on screen state
        NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
        // Polling
        if (screenState >= NFC_POLLING_MODE) {//这里被调用
            // Check if reader-mode is enabled
            if (mReaderModeParams != null) {
                int techMask = 0;
                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
                    techMask |= NFC_POLL_A;
                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
                    techMask |= NFC_POLL_B;
                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
                    techMask |= NFC_POLL_F;
                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
                    techMask |= NFC_POLL_ISO15693;
                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
                    techMask |= NFC_POLL_KOVIO;

                Log.d(TAG, " mReaderModeParams != null   paramsBuilder.setTechMask:"+techMask);

                paramsBuilder.setTechMask(techMask);
                paramsBuilder.setEnableReaderMode(true);
            } else {
            
            Log.d(TAG, " mReaderModeParams == null   paramsBuilder.setTechMask:"+NfcDiscoveryParameters.NFC_POLL_DEFAULT +"   NFC_POLL_DEFAULT");
                paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
                paramsBuilder.setEnableP2p(mIsNdefPushEnabled);
            }
        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
            paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
            // enable P2P for MFM/EDU/Corp provisioning
            paramsBuilder.setEnableP2p(true);
        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
                mNfcUnlockManager.isLockscreenPollingEnabled()) {
            Log.d(TAG, "!!!! SCREEN_STATE_ON_LOCKED setTechMask ");

                
            // For lock-screen tags, no low-power polling
            paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
            paramsBuilder.setEnableLowPowerDiscovery(false);
            paramsBuilder.setEnableP2p(false);
        }

        if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
            // Host routing is always enabled at lock screen or later
            
            Log.d(TAG, "  >= SCREEN_STATE_ON_LOCKED  paramsBuilder.setEnableHostRouting(true) ");
            paramsBuilder.setEnableHostRouting(true);
        }

        return paramsBuilder.build();
    }
因此如果要改成黑屏状态下可以使用NFC的话,只要将变量NFC_POLLING_MODE改成
ScreenStateHelper.SCREEN_STATE_OFF即可,代码如下:

    // minimum screen state that enables NFC polling
    //static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
    static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_OFF;

      但是这样的话,手机会一直不休眠,观察电池的电流和电压发现,一直在跳动,这样在黑屏状态下,手机不会休眠,会很耗电,因此还要优化。

      客户的要求是:当双击物理按键Camera键的时候,可以在黑屏状态下使用NFC十分钟,十分钟之类,差不多关于NFC的工作完成了,之后将状态改回来,即:只能在解锁状态下使用NFC,这样的话就可以黑屏使用NFC又节电。

因此,思路如下:

1、接收物理按键Camera键发送的广播,来判断是双击,并将NFC_POLLING_MODE的最小模式改为ScreenStateHelper.SCREEN_STATE_OFF。

2、需要写一个定时器来处理十分钟之后将NFC_POLLING_MODE的最小模式改为会原来的ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED。

      

因此,首先先定义几个常量,从第185行static final int NFC_POLLING_MODE= ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;处开始修改,修改代码如下:

 // minimum screen state that enables NFC polling
    // edited by ouyang [2015-10-19] start
//    static final int NFC_POLLING_MODE= ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
    //默认为要解锁才能使用NFC
	static final int NFC_POLLING_MODE_DEFALUT = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
	//在黑屏情况下也可以使用NFC
    static final int NFC_POLLING_MODE_SCREEN_OFF = ScreenStateHelper.SCREEN_STATE_OFF;
    //默认能使用NFC时的屏幕状态
    static int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
	
    public static int getNFC_POLLING_MODE() {
		return NFC_POLLING_MODE;
	}
    
	public static void setNFC_POLLING_MODE(int mNFC_POLLING_MODE) {
		NFC_POLLING_MODE = mNFC_POLLING_MODE;
	}
	//是否是双击Camera键
	static boolean isDoublePress=false;
	//从黑屏可用NFC恢复到要解锁才能用NFC的时间
	static final int TIME_TO_Restore_Default_Values=(60*1000)*10;//10分钟  10*1000*60
    // edited by ouyang [2015-10-19] end

第二步:写一个广播接收者来处理物理按键Camera,按下和松开时发出的广播。

因为是要判断双击Camera,所以这里只要接收松开Camera键时发出的广播即可。这个广播是公司自己定义的,定义的广播为:"com.runbo.camera.key.up"。所以现在处理这个广播。因为代码中本来就动态注册了一个广播接收者,因此我们在这个广播接收者种再注册一个Intent即可。代码如下:在第450行

// Intents for all users
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_USER_PRESENT);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        
        //added by ouyang start [2015-10-19]
        //Camera物理键按下后松开  发出的广播
        filter.addAction("com.runbo.camera.key.up");
        //added by ouyang end [2015-10-19] 
       
        registerForAirplaneMode(filter);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);

这样我们处理这个双击 Camera键可以在mReceiver中处理了,在mReceiver中的onReceive方法中,判断action是否是"com.runbo.camera.key.up",2295行代码如下:

 //added by ouyang start [2015-10-19] Camera物理键按下后松开
            else if (action.equals("com.runbo.camera.key.up")) {
				Log.d("oyp", "<----com.runbo.camera.key.up---->");
				Handler checkHandler=new Handler();
				Handler restoreHandler=new Handler();
				
				//单击
				if (!isDoublePress) {
					isDoublePress=true;//500ms之类再单击Camera键的话,就是双击了,直接进入  else语句块
					//500ms后触发该线程,查看是单击还是双击
					Runnable CheckDoubleRunnable=new Runnable(){  
						   @Override  
						   public void run() {  
							if (isDoublePress) {
								Log.i("oyp", "<----Single Press the Camera Key---->");  //显示为单击
							}else{
								Log.i("oyp", "<----Double Press the Camera Key---->");  //显示为双击
							}
							isDoublePress=false;//500ms后在单击Camera键的话 依旧是单击 ,还是进入了 if语句块
						   }   
						};  
					checkHandler.postDelayed(CheckDoubleRunnable, 500);// 500ms内两次单击,触发双击  
				}
				// 500ms内两次单击,触发双击  
				else{
					isDoublePress=false;//双击后,将该值设为false,下次在单击Camera键的话 依旧是单击 ,还是进入了 if语句块
					//设置在屏幕关闭情况下仍然可以使用NFC
					setNFC_POLLING_MODE(NFC_POLLING_MODE_SCREEN_OFF);
					applyRouting(true);
					Log.d("oyp", "2、NFC_POLLING_MODE="+getNFC_POLLING_MODE());
					//10分钟后触发该线程,恢复原来值 
					Runnable RestoreDefaultValues=new Runnable(){  
						   @Override  
						   public void run() {  
							//设置在屏幕解锁情况下可以使用NFC
							setNFC_POLLING_MODE(NFC_POLLING_MODE_DEFALUT);
							applyRouting(true);
							Log.d("oyp", "3、NFC_POLLING_MODE="+getNFC_POLLING_MODE());
						   }   
						};  
					restoreHandler.removeCallbacks(RestoreDefaultValues);//先取消定时器
					restoreHandler.postDelayed(RestoreDefaultValues, TIME_TO_Restore_Default_Values);//10分钟后恢复原来值 
				}
			}
            //added by ouyang end [2015-10-19]

还要将computeDiscoveryParameters()方法中的判断语句改掉,1733行代码如下:

//        if (screenState >= NFC_POLLING_MODE) {
        //edited by ouyang [2015-10-19 11:13:17]
        if (screenState >= getNFC_POLLING_MODE()) {

====================================================================================

上面代码用Handler做十分钟定时器的时候,时间不准确,改用AlarmManager做定时器,下面是修改的代码

//added by ouyang start [2015-11-4] 40分钟后恢复NFC默认值的广播
            else if (action.equals("com.runbo.camera.nfc.restore")) {
            	//设置在屏幕解锁情况下可以使用NFC
            	Log.d("oyp", "<----com.runbo.camera.nfc.restore---->");
				setNFC_POLLING_MODE(NFC_POLLING_MODE_DEFALUT);
				applyRouting(true);
				Log.d("oyp", "3、NFC_POLLING_MODE="+getNFC_POLLING_MODE());

                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date=new Date();
                String time=sdf.format(date);
                Log.d("oyp", "time after="+time);
            }
            //added by ouyang start [2015-10-19] Camera物理键按下后松开
            else if (action.equals("com.runbo.camera.key.up")) {
				Log.d("oyp", "<----com.runbo.camera.key.up---->");
				Handler checkHandler=new Handler();
				Handler restoreHandler=new Handler();
				
				//单击
				if (!isDoublePress) {
					isDoublePress=true;//500ms之类再单击Camera键的话,就是双击了,直接进入  else语句块
					//500ms后触发该线程,查看是单击还是双击
					Runnable CheckDoubleRunnable=new Runnable(){  
						   @Override  
						   public void run() {  
							if (isDoublePress) {
								Log.i("oyp", "<----Single Press the Camera Key---->");  //显示为单击
							}else{
								Log.i("oyp", "<----Double Press the Camera Key---->");  //显示为双击
							}
							isDoublePress=false;//500ms后在单击Camera键的话 依旧是单击 ,还是进入了 if语句块
						   }   
						};  
					checkHandler.postDelayed(CheckDoubleRunnable, 500);// 500ms内两次单击,触发双击  
				}
				// 500ms内两次单击,触发双击  
				else{
					isDoublePress=false;//双击后,将该值设为false,下次在单击Camera键的话 依旧是单击 ,还是进入了 if语句块
					//设置在屏幕关闭情况下仍然可以使用NFC
					setNFC_POLLING_MODE(NFC_POLLING_MODE_SCREEN_OFF);
					applyRouting(true);
					Log.d("oyp", "2、NFC_POLLING_MODE="+getNFC_POLLING_MODE());
					//使用AlarmManager来做定时
					AlarmManager aManager = (AlarmManager)context.getSystemService(Service.ALARM_SERVICE);
					// 指定启动AlarmActivity组件
					Intent nfcRestoreIntent = new Intent("com.runbo.camera.nfc.restore");
					// 创建PendingIntent对象
					PendingIntent pi = PendingIntent.getBroadcast(context, 0, nfcRestoreIntent, 0);
					//设定一个40分钟后的时间
					Calendar calendar=Calendar.getInstance();
					calendar.setTimeInMillis(System.currentTimeMillis());
					calendar.add(Calendar.MINUTE,TIME_TO_Restore_Default_Values);
					//先取消定时器
					//aManager.cancel(pi);
					// 设置AlarmManager将在Calendar对应的时间启动指定组件
					aManager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), pi);	
                
                    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date date=new Date();
                    String time=sdf.format(date);
                    Log.d("oyp", "time before="+time);
					
//					//10分钟后触发该线程,恢复原来值 
//					Runnable RestoreDefaultValues=new Runnable(){  
//						   @Override  
//						   public void run() {  
//							//设置在屏幕解锁情况下可以使用NFC
//							setNFC_POLLING_MODE(NFC_POLLING_MODE_DEFALUT);
//							applyRouting(true);
//							Log.d("oyp", "3、NFC_POLLING_MODE="+getNFC_POLLING_MODE());
//						   }   
//						};  
//					restoreHandler.removeCallbacks(RestoreDefaultValues);//先取消定时器
//					restoreHandler.postDelayed(RestoreDefaultValues, TIME_TO_Restore_Default_Values);//10分钟后恢复原来值
				}
			}
            //added by ouyang end [2015-10-19]


   将Handler的代码注释掉了,改用AlarmManager来做定时器,到达指定的时间后,发送一个“com.runbo.camera.nfc.restore”广播,这个广播也让该广播接收者来接收,因此动态注册广播的代码改成:

      //如果是Hanbang的定制软件
        if (android.os.SystemProperties.isHanbangVersion()) {
            //接收Camera物理键按下后松开,发出的广播 
            filter.addAction("com.runbo.camera.key.up");
            //接收NFC恢复默认值的广播
            filter.addAction("com.runbo.camera.nfc.restore");
        }
        //added by ouyang end [2015-10-19] 


因为之前使用秒来计时,现在使用分钟来计时,因此TIME_TO_Restore_Default_Values改成40,即40分钟

 //从黑屏可用NFC恢复到要解锁才能用NFC的时间
static final int TIME_TO_Restore_Default_Values=40; //40分钟


 

====================================================================================

下面呈上修改后的代码和没修改的代码,经验证,完美!

修改之后的代码如下:



修改之前的代码如下:


               ====================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/ouyang_peng

====================================================================================




相关文章
|
3月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
381 4
|
3月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
10天前
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
121 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
1月前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
96 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
3月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
2月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
2月前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
3月前
|
前端开发 数据处理 Android开发
Flutter前端开发中的调试技巧与工具使用方法,涵盖调试的重要性、基本技巧如打印日志与断点调试、常用调试工具如Android Studio/VS Code调试器和Flutter Inspector的介绍
本文深入探讨了Flutter前端开发中的调试技巧与工具使用方法,涵盖调试的重要性、基本技巧如打印日志与断点调试、常用调试工具如Android Studio/VS Code调试器和Flutter Inspector的介绍,以及具体操作步骤、常见问题解决、高级调试技巧、团队协作中的调试应用和未来发展趋势,旨在帮助开发者提高调试效率,提升应用质量。
95 8
|
3月前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
8月前
|
网络协议 Android开发 数据安全/隐私保护
Android手机上使用Socks5全局代理-教程+软件
Android手机上使用Socks5全局代理-教程+软件
5603 2

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 8
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 9
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 10
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 1
    【02】整体试验思路,在这之前我们发现sec_uid,sec_uid是什么和uid的关系又是什么?相互如何转换?python开发之理论研究试验,如何通过抖音视频下方的用户的UID获得抖音用户的手机号-本系列文章仅供学习研究-禁止用于任何商业用途-仅供学习交流-优雅草卓伊凡
    23
  • 2
    【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
    27
  • 3
    【01】整体试验思路,如何在有UID的情况下获得用户手机号信息,python开发之理论研究试验,如何通过抖音视频下方的用户的UID获得抖音用户的手机号-本系列文章仅供学习研究-禁止用于任何商业用途-仅供学习交流-优雅草卓伊凡
    126
  • 4
    美团面试:手机扫描PC二维码登录,底层原理和完整流程是什么?
    74
  • 5
    MNN-LLM App:在手机上离线运行大模型,阿里巴巴开源基于 MNN-LLM 框架开发的手机 AI 助手应用
    1250
  • 6
    【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
    34
  • 7
    ClKLog支持手机端查询统计数据啦!
    41
  • 8
    OmAgent:轻松构建在终端设备上运行的 AI 应用,赋能手机、穿戴设备、摄像头等多种设备
    240
  • 9
    Mobile-Agent:通过视觉感知实现自动化手机操作,支持多应用跨平台
    343
  • 10
    HTML5实现的手机验证抽奖领券效果源码
    67