Unity +Android studio + 高德地圖 == 地圖顯示和定位

? 初次寫這個,記錄一下 我這個從0基礎的小白,因為公司需要進入unity 與android 交互的大門。

? 之前看的網上的很多東西,太亂而且很多文章有些東西一筆帶過太簡單,所以記錄一下自己的經歷。

1、配置環境和安裝androidstudio 不用說,網上都有。這個還是可以的。

2、下載高德地圖sdk,百度 高德地圖API 根據自己需求下載(下圖為本人下載)

3、創建一個安卓工程,將下載的高德地圖的sdk解壓并將下圖中的jar(AMap3DMap_6.3.0_AMapLocation_4.1.0_20180619)包復制到新建的工程的Project->app->libs里面。將 Unity的jar也導入到 libs 里面(D:\U3D\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes)

4、添加依賴關系,選中導入的兩個jar包,右鍵 add as Library。

5、在Project->app->src->main 中新建一個jniLibs文件夾,如下圖所示將文件包復制進去。

6、基本上差不多了,不要先修改build.grade里面的東西。

7、修改AndroidManifest.xml里面的東西,將所需要的權限加入其中。鏈接里面很清楚。 https://lbs.amap.com/api/android-sdk/guide/create-map/show-map,重要一步記得在里面? 添上一句話

8、當然 在這之前你要申請Key值? 這個 給鏈接? 很簡單,我寫的步驟 是按照我的腦袋里記住的來的 ,可以適當自己調整emmmmm? 是的。:? https://lbs.amap.com/api/android-sdk/gettingstarted ? ??

關鍵點,圈出來!!!!否則 ,后果自費。

9、填入key值之后,繼續走步驟哈? 代碼了,代碼狗啊!!,我建議 如果想要在unity程序中 再創建一個Activity了,作為顯示地圖和定位的Activity? 。MainActivity? extends? Activity(暫時的,等安卓真機測試沒問題就要改成 extends? UnityPlayerActivity!! 一定要是 這個? 。要不 emmmm....出錯了別找我 后果自負!!!!)。

10、顯示 地圖的代碼,下圖這些應該足夠了。該死的簡書 不讓我復制。。。。

11、咳咳貌似可以了,,,,下面給你們看看我的各個Activity,根據這個可以自己寫。

MainActivity:請忽略我的傳值。

定位和顯示地圖的Activity,名字隨便起,但是我的這個activity exends?extends CheckPermissionsActivity implements AMapLocationListener ? ,CheckPermissionsActivity我一會會貼出來。一個老哥幫忙改了下,在這里萬分感謝 我哥。

private AMapLocationClientmlocationClient =null;//定位發起端

private AMapLocationClientOptionmLocationOption =null;//定位參數

private LocationSource.OnLocationChangedListenermListener =null;//定位監聽器

//定位回調字符串

private static StringLocationInfo;

private MapViewmapView;

private AMapaMap;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

? ? setContentView(R.layout.activity_main);

? ? mapView = (MapView) findViewById(R.id.map);//找到地圖控件

//在activity執行onCreate時執行mMapView.onCreate(savedInstanceState),創建地圖

? ? mapView.onCreate(savedInstanceState);

? ? if (aMap ==null) {

aMap =mapView.getMap();

? ? }

aMap.moveCamera(CameraUpdateFactory.zoomTo(16));

? ? btn1 = (Button) findViewById(R.id.button1);

? ? btn1.setOnClickListener(new View.OnClickListener() {

@Override

? ? ? ? public void onClick(View view) {

finish();

? ? ? ? }

});

mlocationClient =new AMapLocationClient(this);

? ? ? ? //初始化定位參數

? ? ? ? mLocationOption =new AMapLocationClientOption();

? ? ? ? //設置定位監聽

? ? ? ? mlocationClient.setLocationListener(this);

? ? ? ? //設置定位模式為高精度模式,Battery_Saving為低功耗模式,Device_Sensors是僅設備模式

? ? ? ? mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);

? ? ? ? //設置定位間隔,單位毫秒,默認為2000ms

? ? ? ? mLocationOption.setInterval(2000);

? ? ? ? //設置定位參數

? ? ? ? mlocationClient.setLocationOption(mLocationOption);

? ? ? ? // 此方法為每隔固定時間會發起一次定位請求,為了減少電量消耗或網絡流量消耗,

// 注意設置合適的定位時間的間隔(最小間隔支持為1000ms),并且在合適時間調用stopLocation()方法來取消定位請求

// 在定位結束后,在合適的生命周期調用onDestroy()方法

// 在單次定位情況下,定位無論成功與否,都無需調用stopLocation()方法移除請求,定位sdk內部會移除

//啟動定位

? ? ? ? mlocationClient.startLocation();

//定位藍點

? ? ? ? BitmapDescriptor bitmapDescriptor3 = BitmapDescriptorFactory.fromResource(R.mipmap.ic_zhujue);

? ? ? ? MyLocationStyle myLocationStyle;

? ? ? ? myLocationStyle =new MyLocationStyle();//初始化定位藍點樣式類myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//連續定位、且將視角移動到地圖中心點,定位點依照設備方向旋轉,并且會跟隨設備移動。(1秒1次定位)如果不設置myLocationType,默認也會執行此種模式。

? ? ? ? myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW);

? ? ? ? myLocationStyle.interval(5000); //設置連續定位模式下的定位間隔,只在連續定位模式下生效,單次定位模式下不會生效。單位為毫秒。

? ? ? ? aMap.setMyLocationStyle(myLocationStyle);//設置定位藍點的Style

? ? ? ? myLocationStyle.radiusFillColor(0);

? ? ? ? //aMap.getUiSettings().setMyLocationButtonEnabled(true);設置默認定位按鈕是否顯示,非必需設置。

? ? ? ? aMap.setMyLocationEnabled(true);// 設置為true表示啟動顯示定位藍點,false表示隱藏定位藍點并不進行定位,默認是false。

? ? ? ? myLocationStyle.myLocationIcon(bitmapDescriptor3);

}

@Override

? ? public void onLocationChanged(AMapLocation location) {

if (null != location) {

StringBuffer sb =new StringBuffer();

? ? ? ? ? ? //errCode等于0代表定位成功,其他的為定位失敗,具體的可以參照官網定位錯誤碼說明

? ? ? ? ? ? if (location.getErrorCode() ==0) {

sb.append("定位成功" +"\n");

? ? ? ? ? ? ? ? sb.append("定位類型: " + location.getLocationType() +"\n");

? ? ? ? ? ? ? ? sb.append("經? ? 度? ? : " + location.getLongitude() +"\n");

? ? ? ? ? ? ? ? sb.append("緯? ? 度? ? : " + location.getLatitude() +"\n");

? ? ? ? ? ? ? ? sb.append("精? ? 度? ? : " + location.getAccuracy() +"米" +"\n");

? ? ? ? ? ? ? ? sb.append("提供者? ? : " + location.getProvider() +"\n");

? ? ? ? ? ? ? ? sb.append("速? ? 度? ? : " + location.getSpeed() +"米/秒" +"\n");

? ? ? ? ? ? ? ? sb.append("角? ? 度? ? : " + location.getBearing() +"\n");

? ? ? ? ? ? ? ? // 獲取當前提供定位服務的衛星個數

? ? ? ? ? ? ? ? sb.append("星? ? 數? ? : " + location.getSatellites() +"\n");

? ? ? ? ? ? ? ? sb.append("國? ? 家? ? : " + location.getCountry() +"\n");

? ? ? ? ? ? ? ? sb.append("省? ? ? ? ? ? : " + location.getProvince() +"\n");

? ? ? ? ? ? ? ? sb.append("市? ? ? ? ? ? : " + location.getCity() +"\n");

? ? ? ? ? ? ? ? sb.append("城市編碼 : " + location.getCityCode() +"\n");

? ? ? ? ? ? ? ? sb.append("區? ? ? ? ? ? : " + location.getDistrict() +"\n");

? ? ? ? ? ? ? ? sb.append("區域 碼? : " + location.getAdCode() +"\n");

? ? ? ? ? ? ? ? sb.append("地? ? 址? ? : " + location.getAddress() +"\n");

? ? ? ? ? ? ? ? sb.append("興趣點? ? : " + location.getPoiName() +"\n");

? ? ? ? ? ? ? ? LocationInfo = sb.toString();

? ? ? ? ? ? ? ? ListMarker.longitude = location.getLatitude();

? ? ? ? ? ? ? ? ListMarker.latitude = location.getLongitude();

? ? ? ? ? ? ? ? //定位完成的時間

? ? ? ? ? ? ? ? sb.append("定位時間: " + Utils.formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") +"\n");

? ? ? ? ? ? }else {

//定位失敗

? ? ? ? ? ? ? ? sb.append("定位失敗" +"\n");

? ? ? ? ? ? ? ? sb.append("錯誤碼:" + location.getErrorCode() +"\n");

? ? ? ? ? ? ? ? sb.append("錯誤信息:" + location.getErrorInfo() +"\n");

? ? ? ? ? ? ? ? sb.append("錯誤描述:" + location.getLocationDetail() +"\n");

? ? ? ? ? ? }

sb.append("***定位質量報告***").append("\n");

? ? ? ? ? ? sb.append("* WIFI開關:").append(location.getLocationQualityReport().isWifiAble() ?"開啟" :"關閉").append("\n");

? ? ? ? ? ? sb.append("* GPS星數:").append(location.getLocationQualityReport().getGPSSatellites()).append("\n");

? ? ? ? ? ? sb.append("* 網絡類型:" + location.getLocationQualityReport().getNetworkType()).append("\n");

? ? ? ? ? ? sb.append("* 網絡耗時:" + location.getLocationQualityReport().getNetUseTime()).append("\n");

? ? ? ? ? ? sb.append("****************").append("\n");

? ? ? ? ? ? //定位之后的回調時間

? ? ? ? ? ? sb.append("回調時間: " + Utils.formatUTC(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") +"\n");

? ? ? ? ? ? //解析定位結果,

? ? ? ? ? ? String result = sb.toString();

? ? ? ? ? ? Log.i("tag", result);

? ? ? ? ? ? System.out.println(MarkerGather.latitude);

? ? ? ? }

}

//調用經度

? ? public double GetInfoxlongitude() {

//? ? ? ? startLocation();

? ? ? ? return ListMarker.longitude;

? ? }

//調用緯度

? ? public double GetInfoylatitude() {

//? ? ? ? startLocation();

? ? ? ? return ListMarker.latitude;

? ? }

/**

* 方法必須重寫

*/

? ? @Override

? ? protected void onResume() {

super.onResume();

? ? ? ? mapView.onResume();

? ? }

/**

* 方法必須重寫

*/

? ? @Override

? ? protected void onPause() {

super.onPause();

? ? ? ? mapView.onPause();

? ? }

/**

* 方法必須重寫

*/

? ? @Override

? ? protected void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);

? ? ? ? mapView.onSaveInstanceState(outState);

? ? }

/**

* 方法必須重寫

*/

? ? @Override

? ? protected void onDestroy() {

super.onDestroy();

? ? ? ? mapView.onDestroy();

? ? ? ? if (null !=mlocationClient )

{

mlocationClient.onDestroy();

? ? ? ? }

}

@Override

? ? public ResourcesgetResources() {

return getBaseContext().getResources();

? ? }

}

12、CheckPermissionsActivity 其實就是動態獲權限,因為android 6.0以上都需要這么搞,別問我為什么,為了安全!!!!至于這個Activity? 自己去看。不解釋 因為這是很詳細 ,蛋疼中....................。

public class CheckPermissionsActivityextends Activity {

/**

* 需要進行檢測的權限數組

*/

? ? protected String[]needPermissions = {

Manifest.permission.ACCESS_COARSE_LOCATION,

? ? ? ? ? ? Manifest.permission.ACCESS_FINE_LOCATION,

? ? ? ? ? ? Manifest.permission.WRITE_EXTERNAL_STORAGE,

? ? ? ? ? ? Manifest.permission.READ_PHONE_STATE

? ? };

? ? private static final int PERMISSON_REQUESTCODE =0;

? ? /**

* 判斷是否需要檢測,防止不停的彈框

*/

? ? private static boolean isNeedCheck =true;

? ? @Override

? ? protected void onResume() {

super.onResume();

? ? ? ? if (Build.VERSION.SDK_INT >=23

? ? ? ? ? ? ? ? && getApplicationInfo().targetSdkVersion >=23) {

if (isNeedCheck) {

checkPermissions(needPermissions);

? ? ? ? ? ? ? ? isNeedCheck =false;

? ? ? ? ? ? }

}

}

/**

*

? ? * @param permissions

? ? * @since 2.5.0

*

*/

? ? private void checkPermissions(String... permissions) {

try {

if (Build.VERSION.SDK_INT >=23

? ? ? ? ? ? ? ? ? ? && getApplicationInfo().targetSdkVersion >=23) {

List needRequestPermissonList = findDeniedPermissions(permissions);

? ? ? ? ? ? ? ? if (null != needRequestPermissonList

&& needRequestPermissonList.size() >0) {

String[] array = needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]);

? ? ? ? ? ? ? ? ? ? Method method = getClass().getMethod("requestPermissions", new Class[]{String[].class, int.class});

? ? ? ? ? ? ? ? ? ? method.invoke(this, array, PERMISSON_REQUESTCODE);

? ? ? ? ? ? ? ? }

}

}catch (Throwable e) {

}

}

/**

* 獲取權限集中需要申請權限的列表

*

? ? * @param permissions

? ? * @return

? ? * @since 2.5.0

*

*/

? ? private ListfindDeniedPermissions(String[] permissions) {

List needRequestPermissonList =new ArrayList();

? ? ? ? if (Build.VERSION.SDK_INT >=23

? ? ? ? ? ? ? ? && getApplicationInfo().targetSdkVersion >=23){

try {

for (String perm : permissions) {

Method checkSelfMethod = getClass().getMethod("checkSelfPermission", String.class);

? ? ? ? ? ? ? ? ? ? Method shouldShowRequestPermissionRationaleMethod = getClass().getMethod("shouldShowRequestPermissionRationale",

? ? ? ? ? ? ? ? ? ? ? ? ? ? String.class);

? ? ? ? ? ? ? ? ? ? if ((Integer)checkSelfMethod.invoke(this, perm) != PackageManager.PERMISSION_GRANTED

? ? ? ? ? ? ? ? ? ? ? ? ? ? || (Boolean)shouldShowRequestPermissionRationaleMethod.invoke(this, perm)) {

needRequestPermissonList.add(perm);

? ? ? ? ? ? ? ? ? ? }

}

}

catch (Throwable e) {

}

}

return needRequestPermissonList;

? ? }

/**

* 檢測是否所有的權限都已經授權

? ? * @param grantResults

? ? * @return

? ? * @since 2.5.0

*

*/

? ? private boolean verifyPermissions(int[] grantResults) {

for (int result : grantResults) {

if (result != PackageManager.PERMISSION_GRANTED) {

isNeedCheck =false;

return false;

? ? ? ? ? ? }

else

? ? ? ? ? ? {

isNeedCheck =true;

? ? ? ? ? ? }

}

return true;

? ? }

@TargetApi(23)

public void onRequestPermissionsResult(int requestCode,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? String[] permissions, int[] paramArrayOfInt) {

if (requestCode ==PERMISSON_REQUESTCODE) {

isNeedCheck =false;

? ? ? ? ? ? if (!verifyPermissions(paramArrayOfInt)) {

//? ? ? ? ? ? ? ? showMissingPermissionDialog();

? ? ? ? ? ? ? ? isNeedCheck =false;

? ? ? ? ? ? }

}

}

/**

* 顯示提示信息

*

? ? * @since 2.5.0

*

*/

? ? private void showMissingPermissionDialog() {

AlertDialog.Builder builder =new AlertDialog.Builder(this);

//? ? ? ? builder.setTitle(R.string.notifyTitle);

//? ? ? ? builder.setMessage(R.string.notifyMsg);

// 拒絕, 退出應用

? ? ? ? builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

@Override

? ? ? ? ? ? ? ? ? ? public void onClick(DialogInterface dialog, int which) {

finish();

? ? ? ? ? ? ? ? ? ? }

});

? ? ? ? builder.setPositiveButton(R.string.setting,

? ? ? ? ? ? ? ? new DialogInterface.OnClickListener() {

@Override

? ? ? ? ? ? ? ? ? ? public void onClick(DialogInterface dialog, int which) {

startAppSettings();

? ? ? ? ? ? ? ? ? ? }

});

? ? ? ? builder.setCancelable(false);

? ? ? ? builder.show();

? ? }

/**

*? 啟動應用的設置

*

? ? * @since 2.5.0

*

*/

? ? private void startAppSettings() {

Intent intent =new Intent(

Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

? ? ? ? intent.setData(Uri.parse("package:" + getPackageName()));

? ? ? ? startActivity(intent);

? ? }

@Override

? ? public boolean onKeyDown(int keyCode, KeyEvent event) {

if(keyCode == KeyEvent.KEYCODE_BACK){

this.finish();

return true;

? ? ? ? }

return super.onKeyDown(keyCode, event);

? ? }

}

13、基本上都差不多了? emmm...... 記得在AndroidManifest.xml中注冊你的每個Activity!!!要不 后果自負啊啊啊啊啊。

14、在MainActivity的 onCreate 函數中調用下? OtherGameLocation()函數 。跑跑試試吧 。真機測試啊 。手機連電腦 ,跑 android? studio 啊? ,記得打開你的開發者模式和usb調試? 記得匹配密碼就差不調可以跑了。點三角號,會顯示出你的機型,跑就可以了。

15、如果成功了啊,就按住9括號里面的改一下 然后? 在將build.gradle里面改成 6 那樣紙的就好了。然后 點擊? buile 里面的 Rebuild Project 完成之后 在點擊buile apk 然后將aar和 AndroidManifest.xml復制到 桌面 等待著 導入unity 中。emmm......unity不用我多說了吧? 。

16、 新建一個unity的工程然后在Accets 文件夾下面創建一個Plugins 文件夾,而后在Plugins里面創建一個android 文件夾,將導出的aar包和 AndroidManifest.xml 導入進去 ,之后呢? ,迂回一下,將你解壓完成的高德地圖里面的jar里面的 assets 文件夾復制一份,丟入unity中和 aar 包他們在一起。

17、之后的事情嗎 簡單的多了, 設置一個按鈕,當點擊按鈕時候 unity 調用 android里面的方法,進入地圖和定位、? button 我就不說了,各位 unity大佬,自行搞定唄emmm.....出事別怪我頭上。。。記得啊 把你MainActivity中的onCreate 的調用的函數刪除啊。

unity 調用安卓的方法:超級簡單。。mmp,我覺得 前兩句就是固定的,call的時候一定看清楚你 的返回值是什么 如果有返回值 那么就要在call<你的返回值類型>,如果要傳參數 就?? jo.Call("你在andoid studio里面的函數名", 傳的參數);?可以多個參數中間用“,”,這樣就調用了android 的方法,別問我為什么這樣可以,也別天吶,怎么可以這么簡單,emmm.......因為? mmp,我也我也很懵逼啊,蛋疼。

AndroidJavaClass jc;? AndroidJavaObject jo;

public void GameCreat() {

jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");

jo = jc.GetStatic("currentActivity");

?jo.Call("OtherGameLocation");

? ? }

18、最后一步,別特么 開心的直接跑unity ,因為你一跑人 unity 就會告訴你: 對不起,請在真機上測試。。。。。。。。

打包 自己搞吧,記得把 sdk和jdk路徑寫上、、好了,打包成功就差不多了 。

特別感謝兩個老哥,幫了我好多的忙。

最后? 別特么問我太難的問題 老子也懵逼啊? 我也是萌新啊 。。。。。。。emmmm.......

一般問題網上都有答案,可以自己百度下,我寫的可能不全 歡迎各位大佬給指正下~~~。 寫的很詳細了 一般按照我說的來的話應該是沒問題的。

成功了的話 ,記得給刷一顆小心啊~~~~~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377