Android定位輔助工具類-------快速實(shí)現(xiàn)第三方定位SDK集成與使用

在開(kāi)發(fā)中,會(huì)遇到一些定位的需求扇住,我們可以使用系統(tǒng)提供的API來(lái)實(shí)現(xiàn)定位功能,但是大部分時(shí)候我們都會(huì)選擇使用第三方定位SDK來(lái)實(shí)現(xiàn)定位功能。比如目前國(guó)內(nèi)常用的定位SDK有百度地圖搜变、高德地圖、騰訊地圖等针炉。

這些定位SDK都有詳細(xì)的接入文檔挠他,使用也很方便,但是我自己在使用時(shí)還是會(huì)有一些問(wèn)題:

1.動(dòng)態(tài)權(quán)限的獲取篡帕。

2.對(duì)SDK的替換殖侵,比如在使用百度的SDK時(shí)出現(xiàn)了一些問(wèn)題,需要替換到高德SDK镰烧,不可能去一個(gè)一個(gè)的替換含有百度定位的界面拢军。

為了讓自己使用這些SDK更舒心,我自己寫(xiě)了一個(gè)定位的輔助工具類怔鳖,既然可以更快速的對(duì)第三方SDK進(jìn)行集成茉唉,也解決的上面的問(wèn)題。

首先,抽取一個(gè)定位回調(diào)監(jiān)聽(tīng)接口度陆,包含了定位成功艾凯、定位失敗、沒(méi)有權(quán)限的回調(diào)方法懂傀。在定位成功時(shí)locationSuccessful()方法會(huì)回調(diào)趾诗,并把 一些定位相關(guān)信息封裝成 LocationModel 通過(guò)傳參傳遞出來(lái)。

public interface LocationCallBackListener {

    void locationSuccessful(LocationModel locationModel);//定位成功

    void locationFailure(String msg);//定位失敗

    void noPermissions();//沒(méi)有定位權(quán)限
}

然后再抽取一個(gè)定位實(shí)現(xiàn)的接口蹬蚁,具體的定位方法需要實(shí)現(xiàn)這個(gè)接口恃泪。

public interface LocationInterface {

    void init(LocationCallBackListener listener); //定位的初始化

    void startLocation();  //開(kāi)始定位

    void stopLocation(); //停止定位

    void destroyLocation();//銷毀定位或一些資源釋放

}

第三,新建一個(gè)類叫LocationHelper,這里面實(shí)現(xiàn)了對(duì)于動(dòng)態(tài)權(quán)限的統(tǒng)一處理和對(duì)LocationInterface接口實(shí)現(xiàn)類的調(diào)用犀斋。
其中 PermissionHelper 權(quán)限處理工具類參考自# android M權(quán)限適配悟泵,簡(jiǎn)單工具類

/**
 * 定位輔助類 判斷是否有定位權(quán)限

 * <p>
 * 使用注意 必須要調(diào)用onRequestPermissionsResult用于獲取權(quán)限回調(diào)
 * <p>
 * 必須要在頁(yè)面關(guān)閉時(shí)調(diào)用destroyLocation方法
 * <p>
 * Created by sx on 2017/8/7.
 */

public class LocationHelper {

    private LocationInterface mLocationInterface;//定位實(shí)現(xiàn)接口

    private PermissionHelper mPreHelper;//權(quán)限請(qǐng)求


    private LocationCallBackListener mLocationCallBackListener;//定位回調(diào)

    //需要進(jìn)行定位功能的權(quán)限
    private List<String> needLocationPermissions;

    public LocationHelper(@NonNull Object obj, @NonNull LocationInterface locationInterface, @NonNull LocationCallBackListener locationCallBackListener) {
        this.mLocationInterface = locationInterface;
        this.mLocationInterface.init(locationCallBackListener);
        this.mLocationCallBackListener = locationCallBackListener;
        needLocationPermissions = new ArrayList<>();
        mPreHelper = new PermissionHelper(obj);
    }


    /**
     * 添加還需要申請(qǐng)的權(quán)限
     *
     * @param permissions
     */
    public void addPermissions(String permissions) {
        needLocationPermissions.add(permissions);
    }

    /**
     * 需要的定位權(quán)限
     */
    private void setLocationPermissions() {
        needLocationPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
        needLocationPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
        needLocationPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

    /**
     * 啟動(dòng)定位
     */
    public void startLocation() {
        if (needRequestPermiss()) {
            setLocationPermissions();
            requestPermissions();
            return;
        }
        mLocationInterface.startLocation();
    }

    /**
     * 請(qǐng)求定位權(quán)限
     */
    private void requestPermissions() {
        mPreHelper.requestPermissions(new PermissionHelper.PermissionListener() {
            @Override
            public void doAfterGrand(String... permission) {
                mLocationInterface.startLocation();
            }

            @Override
            public void doAfterDenied(String... permission) {
                mLocationCallBackListener.noPermissions();
            }
        }, getPermissions());
    }

    private String[] getPermissions() {
        final int size = needLocationPermissions.size();
        String[] arr = needLocationPermissions.toArray(new String[size] );
        return arr;
    }

    /**
     * 是否需要申請(qǐng)權(quán)限
     *
     * @return
     */
    private boolean needRequestPermiss() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

    /**
     * 關(guān)閉定位
     */
    public void stopLocation() {
        mLocationInterface.stopLocation();
    }

    /**
     * 關(guān)閉一些內(nèi)容
     */
    public void destroyLocation() {
        mLocationInterface.destroyLocation();
    }

    /**
     * 獲取權(quán)限回調(diào)
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (mPreHelper == null) return;
        mPreHelper.handleRequestPermissionsResult(requestCode, permissions, grantResults);
    }


}

到這里我們的定位輔助工具類已經(jīng)寫(xiě)好了,讓我們來(lái)看看怎么使用闪水。這里以高德SDK為例糕非。

新建一個(gè)類叫GaoDeLocation并實(shí)現(xiàn)LocationInterface接口,其中主要實(shí)現(xiàn)了包括高德定位SDK的初始化球榆、啟動(dòng)定位朽肥、結(jié)束等一些方法以及定位成功或失敗的判斷。

**
 * 高德定位
 * 
 */
public class GaoDeLocation implements LocationInterface {

    //定位功能
    protected AMapLocationClient locationClient = null;

    @Override
    public void init(final LocationCallBackListener listener) {
        //初始化client
        locationClient = new AMapLocationClient(MyApplication.getInstance());
        //設(shè)置定位參數(shù)
        locationClient.setLocationOption(getDefaultOption());
        // 設(shè)置定位監(jiān)聽(tīng)
        locationClient.setLocationListener(new AMapLocationListener() {
            @Override
            public void onLocationChanged(AMapLocation aMapLocation) {
                if (null != aMapLocation && aMapLocation.getErrorCode() == 0) {  //定位成功
                    listener.locationSuccessful(transitionModel(aMapLocation));
                } else {
                    if (aMapLocation != null) {
                        listener.locationFailure(aMapLocation.getErrorInfo());
                        return;
                    }
                    listener.locationFailure("定位失敗");
                }
                //停止定位
                stopLocation();
            }
        });
    }

    @Override
    public void startLocation() {
        locationClient.startLocation();
    }

    @Override
    public void stopLocation() {
        locationClient.stopLocation();
    }

    @Override
    public void destroyLocation() {
        if (null != locationClient) {
            locationClient.onDestroy();
            locationClient = null;
        }
    }

    /**
     * 默認(rèn)定位參數(shù)
     *
     * @return
     */
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可選持钉,設(shè)置定位模式衡招,可選的模式有高精度、僅設(shè)備每强、僅網(wǎng)絡(luò)始腾。默認(rèn)為高精度模式
        mOption.setGpsFirst(false);//可選,設(shè)置是否gps優(yōu)先空执,只在高精度模式下有效浪箭。默認(rèn)關(guān)閉
        mOption.setHttpTimeOut(30000);//可選,設(shè)置網(wǎng)絡(luò)請(qǐng)求超時(shí)時(shí)間辨绊。默認(rèn)為30秒奶栖。在僅設(shè)備模式下無(wú)效
        mOption.setInterval(2000);//可選,設(shè)置定位間隔门坷。默認(rèn)為2秒
        mOption.setNeedAddress(true);//可選宣鄙,設(shè)置是否返回逆地理地址信息。默認(rèn)是ture
        mOption.setOnceLocation(true);//可選默蚌,設(shè)置是否單次定位冻晤。默認(rèn)是false
        mOption.setOnceLocationLatest(false);//可選,設(shè)置是否等待wifi刷新绸吸,默認(rèn)為false.如果設(shè)置為true,會(huì)自動(dòng)變?yōu)閱未味ㄎ槐腔。掷m(xù)定位時(shí)不要使用
        mOption.setLocationCacheEnable(false);  // 設(shè)置是否開(kāi)啟緩存
        AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可選设江, 設(shè)置網(wǎng)絡(luò)請(qǐng)求的協(xié)議∥率可選HTTP或者HTTPS。默認(rèn)為HTTP
        return mOption;
    }

    /**
     * 把高德定位model轉(zhuǎn)換為 自用model
     *
     * @return
     */
    private LocationModel transitionModel(AMapLocation aMapLocation) {
        LocationModel locationModel = new LocationModel();
        locationModel.setCity(aMapLocation.getCity());
        locationModel.setProvince(aMapLocation.getProvince());
        locationModel.setDistrict(aMapLocation.getDistrict());
        locationModel.setLatitude(aMapLocation.getLatitude() + "");
        locationModel.setLongitude(aMapLocation.getLongitude() + "");
        return locationModel;
    }

}

這里說(shuō)明一下transitionModel() 方法蜻势,這是為了把高德SDK的定位model轉(zhuǎn)為自己的model撑刺,因?yàn)椴煌琒DK的定位model是不同,這里做一下轉(zhuǎn)換握玛,就是為了解決快速替換的問(wèn)題够傍。

**用于定位
 * Created by cdkj on 2017/11/7.
 */

public class LocationModel implements Parcelable {

    private String city;

    private String province;

    private String district;

    private String latitude;

    private String longitude;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getDistrict() {
        return district;
    }

    public void setDistrict(String district) {
        this.district = district;
    }

    public String getLatitude() {
        return latitude;
    }

    public void setLatitude(String latitude) {
        this.latitude = latitude;
    }

    public String getLongitude() {
        return longitude;
    }

    public void setLongitude(String longitude) {
        this.longitude = longitude;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.city);
        dest.writeString(this.province);
        dest.writeString(this.district);
        dest.writeString(this.latitude);
        dest.writeString(this.longitude);
    }

    public LocationModel() {
    }

    protected LocationModel(Parcel in) {
        this.city = in.readString();
        this.province = in.readString();
        this.district = in.readString();
        this.latitude = in.readString();
        this.longitude = in.readString();
    }

    public static final Creator<LocationModel> CREATOR = new Creator<LocationModel>() {
        @Override
        public LocationModel createFromParcel(Parcel source) {
            return new LocationModel(source);
        }

        @Override
        public LocationModel[] newArray(int size) {
            return new LocationModel[size];
        }
    };
}

GaoDeLocation類實(shí)現(xiàn)之后就可以使用LocationHelper類了。

先 new 一個(gè) LocationHelper對(duì)象挠铲,第二個(gè)參數(shù)傳入剛才的GaoDeLocation類冕屯。在需要開(kāi)始定位的地方調(diào)用 mLocationHelperr.startLocation() 方法就可以進(jìn)行定位了。

   LocationHelper  mLocationHelperr = new LocationHelper(MainActivity.this, new GaoDeLocation(), new LocationCallBackListener() {
            @Override
            public void locationSuccessful(LocationModel locationModel) {
                mainBinding.tvLocationInfo.setText("高德定位結(jié)果" + locationModel.getCity());
            }

            @Override
            public void locationFailure(String msg) {
                mainBinding.tvLocationInfo.setText("高德定位結(jié)果" + msg);
            }

            @Override
            public void noPermissions() {
                mainBinding.tvLocationInfo.setText("高德定位結(jié)果沒(méi)有定位權(quán)限");
            }
        });

    mLocationHelperr.startLocation();

以上就實(shí)現(xiàn)了高德定位的過(guò)程拂苹,并且連權(quán)限管理也一并處理了安聘,當(dāng)然如果想把高德SDK替換成百度SDK也是非常簡(jiǎn)單的。我們可以把 GaoDeLocation 類 替換成 BaiDuLocation 類瓢棒,這樣就完成了替換浴韭。

public class BaiDuLocation implements LocationInterface {
    public LocationClient mLocationClient = null;

    @Override
    public void init(final LocationCallBackListener listener) {
        mLocationClient = new LocationClient(MyApplication.getInstance());
        mLocationClient.setLocOption(getLocationClientOption());
        //mLocationClient為第二步初始化過(guò)的LocationClient對(duì)象
        //需將配置好的LocationClientOption對(duì)象,通過(guò)setLocOption方法傳遞給LocationClient對(duì)象使用
        //更多LocationClientOption的配置脯宿,請(qǐng)參照類參考中LocationClientOption類的詳細(xì)說(shuō)明
        //聲明LocationClient類
        mLocationClient.registerLocationListener(new BDAbstractLocationListener() {
            @Override
            public void onReceiveLocation(BDLocation location) {

                if (location == null) {
                    return;
                }
                int errorCode = location.getLocType();
                //獲取定位類型念颈、定位錯(cuò)誤返回碼,具體信息可參照類參考中BDLocation類中的說(shuō)明
                Log.i("location", errorCode + "");
                if (errorCode == 61 || errorCode == 161) {
                    listener.locationSuccessful(transitionModel(location));
                } else {
                    listener.locationFailure("定位失敗");
                }
                stopLocation();
            }
        });
    }

    @NonNull
    private LocationClientOption getLocationClientOption() {
        LocationClientOption option = new LocationClientOption();

        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可選连霉,設(shè)置定位模式榴芳,默認(rèn)高精度
//LocationMode.Hight_Accuracy:高精度;
//LocationMode. Battery_Saving:低功耗跺撼;
//LocationMode. Device_Sensors:僅使用設(shè)備窟感;

        option.setCoorType("bd09ll");
//可選,設(shè)置返回經(jīng)緯度坐標(biāo)類型歉井,默認(rèn)gcj02
//gcj02:國(guó)測(cè)局坐標(biāo)肌括;
//bd09ll:百度經(jīng)緯度坐標(biāo);
//bd09:百度墨卡托坐標(biāo)酣难;
//海外地區(qū)定位谍夭,無(wú)需設(shè)置坐標(biāo)類型,統(tǒng)一返回wgs84類型坐標(biāo)

        option.setScanSpan(5000);
//可選憨募,設(shè)置發(fā)起定位請(qǐng)求的間隔紧索,int類型,單位ms
//如果設(shè)置為0菜谣,則代表單次定位珠漂,即僅定位一次晚缩,默認(rèn)為0
//如果設(shè)置非0,需設(shè)置1000ms以上才有效

        option.setOpenGps(true);
//可選媳危,設(shè)置是否使用gps荞彼,默認(rèn)false
//使用高精度和僅用設(shè)備兩種定位模式的,參數(shù)必須設(shè)置為true

        option.setLocationNotify(true);
//可選待笑,設(shè)置是否當(dāng)GPS有效時(shí)按照1S/1次頻率輸出GPS結(jié)果鸣皂,默認(rèn)false

        option.setIgnoreKillProcess(false);
//可選,定位SDK內(nèi)部是一個(gè)service暮蹂,并放到了獨(dú)立進(jìn)程寞缝。
//設(shè)置是否在stop的時(shí)候殺死這個(gè)進(jìn)程,默認(rèn)(建議)不殺死仰泻,即setIgnoreKillProcess(true)
        option.setWifiCacheTimeOut(5 * 60 * 1000);
//可選荆陆,7.2版本新增能力
//如果設(shè)置了該接口,首次啟動(dòng)定位時(shí)集侯,會(huì)先判斷當(dāng)前WiFi是否超出有效期被啼,若超出有效期,會(huì)先重新掃描WiFi棠枉,然后定位

        option.setEnableSimulateGps(false);

        option.setIsNeedAddress(true);

//可選趟据,設(shè)置是否需要過(guò)濾GPS仿真結(jié)果,默認(rèn)需要术健,即參數(shù)為false
        return option;
    }

    @Override
    public void startLocation() {
        mLocationClient.start();
    }

    @Override
    public void stopLocation() {
        mLocationClient.stop();
    }

    @Override
    public void destroyLocation() {
        mLocationClient.stop();
        mLocationClient = null;
    }

    /**
     * 把百度定位model轉(zhuǎn)換為 自用model
     *
     * @return
     */
    private LocationModel transitionModel(BDLocation bdLocation) {
        LocationModel locationModel = new LocationModel();
        locationModel.setCity(bdLocation.getCity());
        locationModel.setProvince(bdLocation.getProvince());
        locationModel.setDistrict(bdLocation.getDistrict());
        locationModel.setLatitude(bdLocation.getLatitude() + "");
        locationModel.setLongitude(bdLocation.getLongitude() + "");
        return locationModel;
    }
}

當(dāng)然汹碱,在使用時(shí)還有兩點(diǎn)需要注意:

1:權(quán)限的處理回調(diào),我們需要在頁(yè)面的 onRequestPermissionsResult 方法中調(diào)用mLocationHelper的onRequestPermissionsResult() 方法荞估,這樣就實(shí)現(xiàn)了權(quán)限的處理咳促。

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (mLocationHelper != null) {
            mLocationHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

2:對(duì)資源的釋放,在頁(yè)面結(jié)束或銷毀時(shí)調(diào)用mLocationHelper.destroyLocation()方法實(shí)現(xiàn)一些資源的釋放勘伺。

    @Override
    protected void onDestroy() {
        super.onDestroy();
         if (mLocationHelper != null) {
             mGdLocationHelper.destroyLocation()跪腹;
        }
    }

以上就是定位輔助類的實(shí)現(xiàn)及使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末飞醉,一起剝皮案震驚了整個(gè)濱河市冲茸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缅帘,老刑警劉巖轴术,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钦无,居然都是意外死亡逗栽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門失暂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)彼宠,“玉大人鳄虱,你說(shuō)我怎么就攤上這事∑鞠浚” “怎么了拙已?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)摧冀。 經(jīng)常有香客問(wèn)我倍踪,道長(zhǎng),這世上最難降的妖魔是什么按价? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任惭适,我火速辦了婚禮笙瑟,結(jié)果婚禮上楼镐,老公的妹妹穿的比我還像新娘。我一直安慰自己往枷,他們只是感情好框产,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著错洁,像睡著了一般秉宿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屯碴,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天描睦,我揣著相機(jī)與錄音,去河邊找鬼导而。 笑死忱叭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的今艺。 我是一名探鬼主播韵丑,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼虚缎!你這毒婦竟也來(lái)了撵彻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤实牡,失蹤者是張志新(化名)和其女友劉穎陌僵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體创坞,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拾弃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了摆霉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豪椿。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奔坟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搭盾,到底是詐尸還是另有隱情咳秉,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布鸯隅,位于F島的核電站澜建,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蝌以。R本人自食惡果不足惜炕舵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跟畅。 院中可真熱鬧咽筋,春花似錦、人聲如沸徊件。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)虱痕。三九已至睹耐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間部翘,已是汗流浹背硝训。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留新思,地道東北人窖梁。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像表牢,于是被迫代替她去往敵國(guó)和親窄绒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容