最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android如何實(shí)現(xiàn)模擬定位

 更新時(shí)間:2021年05月06日 09:47:39   作者:陳文管  
這篇文章主要介紹了Android如何實(shí)現(xiàn)模擬定位,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下

在導(dǎo)航測(cè)試場(chǎng)景中經(jīng)常需要定位模擬和路線回放,記錄下通過LocationManager.setTestProviderLocation()方法實(shí)現(xiàn)模擬地位,如果要測(cè)試的應(yīng)用不支持TestProviderLocation模擬位置輸入,可以考慮從HAL層入手,hook系統(tǒng)默認(rèn)的GPS實(shí)現(xiàn)。

一、Android模擬權(quán)限開啟配置

在Android6.0以下的版本中,需要在設(shè)置中勾選模擬定位的開關(guān),在6.0以上就改成了選擇模擬定位的應(yīng)用,對(duì)應(yīng)的開啟配置方式也不一樣,相同的是在AndroidManifest.xml都需要配置以下兩個(gè)權(quán)限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

1)Android 6.0以下開啟模擬定位開關(guān)

Settings.Secure.putInt(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 1);

通過這種方式去開啟模擬定位需要在AndroidManifest.xml中配置以下系統(tǒng)權(quán)限,應(yīng)用還需要經(jīng)過系統(tǒng)簽名,對(duì)于非系統(tǒng)應(yīng)用不能通過這種實(shí)現(xiàn)方式。

android:sharedUserId="android.uid.system"

<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />

涉及到這種操作可以通過adb shell命令的方式配置來繞過系統(tǒng)權(quán)限配置:

adb shell settings put secure mock_location 1

2)Android 6.0以上代碼配置選擇模擬定位的應(yīng)用

在6.0以上的Android版本就需要設(shè)置指定包名的mock_location權(quán)限為allow。

try {
    String mockLocationPkgName = getPackageName();
    PackageManager mPackageManager = getPackageManager();
    final ApplicationInfo ai = mPackageManager.getApplicationInfo(
            mockLocationPkgName, PackageManager.MATCH_DISABLED_COMPONENTS);
    AppOpsManager mAppsOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
    mAppsOpsManager.setMode(AppOpsManager.OPSTR_MOCK_LOCATION, ai.uid,
            mockLocationPkgName, AppOpsManager.MODE_ALLOWED);
} catch (PackageManager.NameNotFoundException e) {
    /* ignore */
}

同時(shí)在AndroidManifest.xml中還需要配置如下權(quán)限,可惜這種方式也是需要經(jīng)過系統(tǒng)簽名和源碼一起編譯,只有系統(tǒng)層級(jí)的應(yīng)用才可以使用。

<uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />

為了在設(shè)置界面模擬定位選項(xiàng)中顯示模擬定位的應(yīng)用,需要配置ACCESS_MOCK_LOCATION權(quán)限。

<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

以上配置也可以通過adb shell命令去實(shí)現(xiàn),<package> 參數(shù)用自己應(yīng)用的包名替換。

adb shell appops set <package> android:mock_location allow

關(guān)閉模擬定位權(quán)限,用如下命令:

adb shell appops set <package> android:mock_location deny

要查詢有哪些應(yīng)用開啟了模擬定位權(quán)限,用如下命令:

adb shell appops query-op android:mock_location allow

執(zhí)行后會(huì)輸出應(yīng)用的包名列表參數(shù)。

二、Android模擬定位實(shí)現(xiàn)

1)模擬定位開關(guān)檢查

首先是代碼中先判斷模擬定位權(quán)限是否開啟,6.0以上的只能通過添加定位監(jiān)聽是否有異常來判斷。

boolean mockPermission = false;
if (Build.VERSION.SDK_INT <= 22) {//6.0以下
    mockPermission = Settings.Secure.getInt(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
} else {
    try {
        LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            mockPermission = false;            
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
            }
            @Override
            public void onStatusChanged(String s, int i, Bundle bundle) {
            }
            @Override
            public void onProviderEnabled(String s) {
            }
            @Override
            public void onProviderDisabled(String s) {
            }
        });
        mockPermission = true;
    } catch (SecurityException e) {
        mockPermission = false;
    }
}

可以看下添加定位監(jiān)聽的源碼實(shí)現(xiàn),以Android 7.0的源碼實(shí)現(xiàn)做參考,LocationManager調(diào)用接口之后,最終是調(diào)用到LocationManagerService,在requestLocationUpdates 方法或 getLastLocation 方法中都有checkPackageName方法的調(diào)用

private void checkPackageName(String packageName) {
    if (packageName == null) {
        throw new SecurityException("invalid package name: " + packageName);
    }
    int uid = Binder.getCallingUid();
    String[] packages = mPackageManager.getPackagesForUid(uid);
    if (packages == null) {
        throw new SecurityException("invalid UID " + uid);
    }
    for (String pkg : packages) {
        if (packageName.equals(pkg)) return;
    }
    throw new SecurityException("invalid package name: " + packageName);
}

如果調(diào)用requestLocationUpdates方法的應(yīng)用沒有模擬定位的權(quán)限,就會(huì)報(bào)SecurityException異常,另外requestLocationUpdates需要在主線程中調(diào)用,如果在子線程中調(diào)用,還需要傳一個(gè)looper參數(shù),不然在實(shí)例化ListenerTransport的時(shí)候會(huì)報(bào)錯(cuò)。

看下ListenerTransport的構(gòu)造函數(shù),如果在子線程中添加監(jiān)聽,又沒有傳Loop,初始化mListenerHandler的時(shí)候就會(huì)報(bào)異常。

ListenerTransport(LocationListener listener, Looper looper) {
    mListener = listener;
    if (looper == null) {
        mListenerHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                _handleMessage(msg);
            }
        };
    } else {
        mListenerHandler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                _handleMessage(msg);
            }
        };
    }
}

接著添加對(duì)應(yīng)的Provider,設(shè)置開關(guān)狀態(tài)為true,配置狀態(tài)為AVAILABLE。

LocationProvider provider = locationManager.getProvider(LocationManager.GPS_PROVIDER);
if (provider != null) {
    locationManager.addTestProvider(
        provider.getName()
        , provider.requiresNetwork()
        , provider.requiresSatellite()
        , provider.requiresCell()
        , provider.hasMonetaryCost()
        , provider.supportsAltitude()
        , provider.supportsSpeed()
        , provider.supportsBearing()
        , provider.getPowerRequirement()
        , provider.getAccuracy());
} else {
    locationManager.addTestProvider(LocationManager.GPS_PROVIDER, true, true, false, false, true, true,
        true, Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
}
locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);
locationManager.setTestProviderStatus(LocationManager.GPS_PROVIDER, LocationProvider.AVAILABLE, null, System.currentTimeMillis());

2)setTestProviderLocation調(diào)用

調(diào)用代碼示例如下,經(jīng)緯度、車速、定位準(zhǔn)確性、方位、海拔參數(shù)根據(jù)實(shí)際需求設(shè)置。

Location loc = new Location(LocationManager.GPS_PROVIDER);
loc.setLongitude(24.522301);
loc.setLatitude(118.115756);
loc.setSpeed(60);
loc.setAccuracy(Criteria.ACCURACY_HIGH);
loc.setBearing(0);
loc.setAltitude(0);
loc.setTime(System.currentTimeMillis());
if (Build.VERSION.SDK_INT >= 17) {
    loc.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
}
locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER,loc);

來看下為什么需要設(shè)置elapsedRealtimeNanos和time參數(shù)。在SDK版本17以下,Location(Android 4.1.1)是沒有setElapsedRealtimeNanos這個(gè)方法的,在SDK版本17開始,Location(Android 4.2)加了這個(gè)方法,在調(diào)用setTestProviderLocation設(shè)置定位信息的時(shí)候,Android SDK版本17以上會(huì)做定位參數(shù)是否完整的校驗(yàn),17以下的版本自動(dòng)做補(bǔ)足,17開始的版本直接拋異常。

public void setTestProviderLocation(String provider, Location loc) {
    if (!loc.isComplete()) {
        IllegalArgumentException e = new IllegalArgumentException(
            "Incomplete location object, missing timestamp or accuracy? " + loc);
        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
            // just log on old platform (for backwards compatibility)
            Log.w(TAG, e);
            loc.makeComplete();
        } else {
            // really throw it!
            throw e;
        }
    }
    try {
        mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

接著看下Location類中makeComplete和isComplete做的邏輯處理,isComplete里面有provider,Accuracy,mTime和mElapsedRealtimeNanos的判斷。

@SystemApi
public void makeComplete() {
    if (mProvider == null) mProvider = "?";
    if (!hasAccuracy()) {
        mFieldsMask |= HAS_ACCURACY_MASK;
        mAccuracy = 100.0f;
    }
    if (mTime == 0) mTime = System.currentTimeMillis();
    if (mElapsedRealtimeNanos == 0) mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
}
@SystemApi
public boolean isComplete() {
    if (mProvider == null) return false;
    if (!hasAccuracy()) return false;
    if (mTime == 0) return false;
    if (mElapsedRealtimeNanos == 0) return false;
    return true;
}

以上是就是單個(gè)點(diǎn)的模擬定位實(shí)現(xiàn),如果要實(shí)現(xiàn)路線回放模擬,只要在后臺(tái)請(qǐng)求到路線定位點(diǎn)數(shù)組數(shù)據(jù)之后,每隔1秒刷新調(diào)用setTestProviderLocation接口就可以了。

在模擬定位操作完畢之后,需要移除模擬定位對(duì)象,避免定位信息還是使用模擬定位接口的參數(shù),如果沒有移除下一次使用的時(shí)候又調(diào)用添加同名的Provider也會(huì)拋異常。

locationManager.removeTestProvider(LocationManager.GPS_PROVIDER);

以上就是Android如何實(shí)現(xiàn)模擬定位的詳細(xì)內(nèi)容,更多關(guān)于Android 模擬定位的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android UI更新的幾種方法總結(jié)

    Android UI更新的幾種方法總結(jié)

    這篇文章主要介紹了Android UI更新的幾種方法總結(jié)的相關(guān)資料,這里對(duì)Android UI 的幾種更新列出了,并附實(shí)例代碼,需要的朋友可以參考下
    2016-11-11
  • android實(shí)現(xiàn)QQ微信側(cè)滑刪除效果

    android實(shí)現(xiàn)QQ微信側(cè)滑刪除效果

    這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)QQ微信側(cè)滑刪除效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android實(shí)現(xiàn)自定義倒計(jì)時(shí)

    Android實(shí)現(xiàn)自定義倒計(jì)時(shí)

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)自定義倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • 使用RecyclerView實(shí)現(xiàn)瀑布流高度自適應(yīng)

    使用RecyclerView實(shí)現(xiàn)瀑布流高度自適應(yīng)

    這篇文章主要為大家詳細(xì)介紹了使用RecyclerView實(shí)現(xiàn)瀑布流高度自適應(yīng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Android下SDL2實(shí)現(xiàn)五子棋游戲

    Android下SDL2實(shí)現(xiàn)五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了Android下SDL2實(shí)現(xiàn)五子棋游戲的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-02-02
  • Android Jetpack組件庫LiveData源碼深入探究

    Android Jetpack組件庫LiveData源碼深入探究

    LiveData是Jetpack組件的一部分,更多的時(shí)候是搭配ViewModel來使用,相對(duì)于Observable,LiveData的最大優(yōu)勢(shì)是其具有生命感知的,換句話說,LiveData可以保證只有在組件( Activity、Fragment、Service)處于活動(dòng)生命周期狀態(tài)的時(shí)候才會(huì)更新數(shù)據(jù)
    2022-09-09
  • Android中實(shí)現(xiàn)長(zhǎng)按修改ListView對(duì)象的內(nèi)容

    Android中實(shí)現(xiàn)長(zhǎng)按修改ListView對(duì)象的內(nèi)容

    這篇文章主要給大家介紹了在Android中實(shí)現(xiàn)長(zhǎng)按修改ListView對(duì)象內(nèi)容的相關(guān)資料,文中給出了完整的示例代碼,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。
    2017-02-02
  • Android 滑動(dòng)返回Activity的實(shí)現(xiàn)代碼

    Android 滑動(dòng)返回Activity的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Android 滑動(dòng)返回Activity的實(shí)現(xiàn)代碼的相關(guān)資料,這里是訪微信滑動(dòng)返回主頁的功能,需要的朋友可以參考下
    2017-07-07
  • Android Notification使用方法總結(jié)

    Android Notification使用方法總結(jié)

    這篇文章主要介紹了Android Notification使用方法總結(jié)的相關(guān)資料,這里提供了四種使用方法,需要的朋友可以參考下
    2017-09-09
  • 代碼從windows下visual studio到andriod平臺(tái)遷移實(shí)現(xiàn)步驟

    代碼從windows下visual studio到andriod平臺(tái)遷移實(shí)現(xiàn)步驟

    這篇文章主要介紹了代碼從windows下visual studio到andriod平臺(tái)遷移的修改記錄的相關(guān)資料,需要的朋友可以參考下
    2017-01-01

最新評(píng)論

彭水| 徐汇区| 平阳县| 同心县| 鄱阳县| 百色市| 高州市| 永昌县| 新昌县| 陇南市| 乌拉特中旗| 阿拉尔市| 庐江县| 沿河| 开平市| 开封县| 民勤县| 柳州市| 河北区| 云霄县| 浏阳市| 土默特左旗| 广丰县| 金乡县| 威宁| 丰台区| 开阳县| 礼泉县| 博乐市| 海兴县| 木里| 泗水县| 南汇区| 香港 | 甘孜| 太仆寺旗| 高青县| 南部县| 沧源| 天等县| 元阳县|