Android适配全面总结(三)----ROM适配

版权声明:本文为博主原创文章(部分引用他人博文,已加上引用说明),未经博主允许不得转载。https://www.jianshu.com/p/f9c67a4b908e

转载请标明出处:
https://www.jianshu.com/p/f9c67a4b908e
本文出自 AWeiLoveAndroid的博客



第一篇文章讲了 Android适配全面总结(一)----屏幕适配
上一篇文章讲了 Android适配全面总结(二)----版本适配

这一篇文章讲一下 ROM适配。


Android是开源的,不同的手机厂商都有自己定制的系统,所以这就给开发者带来了ROM适配难题。在一些群里面经常看到有人因为手机适配问题,说这个手机坑,那个手机坑,其实那是没有对ROM定制系统的一些变更了解,导致了盲目的说出这些指责的话。如果你熟悉了,也就会少走很多弯路。下面这篇文章就来讲一下几个主流手机的ROM适配问题。


一、手机平台相关文档

(一)小米

(1)文档

1、小米开发者文档
2、开发人员必看:《小米应用开发者文档》 ,在这里可以找到在小米手机上开发、分发应用的相关文档。
3、常见问题
4、小米帐号场景化登录
5、技术文档


(二)华为

(1)文档

1、 APK固件及分辨率适配说明
2、 华为全面屏适配技术指导
3、 华为刘海屏手机安卓O版本适配指导
4、 谷歌强制升级TargetSdkVersion适配指导
5、 Android P版本非SDK接口管控特性解读及适配指导
6、 Android P版本应用兼容性适配技术指导
7、华为桌面角标开发指导书

(2)问题

1、华为部分设备不打印Log

部分的华为设备工程模式下log是关闭的,华为部分设备不打印Log的解决方案:

1.如果是华为手机,进入拨号界面输入:*#*#2846579#*#*进入页面设置。
2.如果是华为pad,进入计算器输入:()()2846579()()= 进入页面设置。
2、华为手机获取拍照权限后拍照,返回值为空

问题起源:
开发中遇到了需要拍照和从图库中选择图片展示并上传的功能,其他手机测试没问题,华为手机获取拍照权限后拍照,返回值为空。

问题分析:
原来是华为在7.0以后的系统中,对于拍照后返回的图片也做了权限处理。所以说,华为7.0在拍照的时候,不仅要拿到拍照 CAMERA 的权限,还要拿到读写文件的权限 WRITE_EXTERNAL_STORAGE

解决方法部分代码如下:

//声明两个常量
public static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 0x0001;
public static final int MY_PERMISSIONS_REQUEST_CALL_PHONE2 = 0x0002;

//设置权限
public void setTakePhonePermissions(Context context) {  
    if (Build.VERSION.SDK_INT >= 23) {  
        int checkCallPhonePermission = ContextCompat.checkSelfPermission(context,  
                Manifest.permission.CAMERA);  
        if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {  
            ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.CAMERA,}  
                    , MY_PERMISSIONS_REQUEST_CALL_PHONE);  
        } else if (ContextCompat.checkSelfPermission(context,  
                Manifest.permission.WRITE_EXTERNAL_STORAGE)  
                != PackageManager.PERMISSION_GRANTED) {  
            ActivityCompat.requestPermissions(context,  
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA},  
                    MY_PERMISSIONS_REQUEST_CALL_PHONE2);  
        } else {  
            takePhoto();  
        }  
    //小于23的不需要动态权限
    } else {  
        takePhoto();  
    }  
}  
3、华为Android7.0手机打开摄像头拍照闪退问题。
4、华为手机Android8.0 使用代码安装APK闪退问题

更新版本APK自动安装的时候,在安卓6.0、7.0下都OK,唯独在华为安卓8.0手机闪退。

解决方案: 只要在Mainfest.xml 中加入请求安装权限就OK了

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

  • ★★ 关于闪退的小结:
    1. 在Android 7.0(及以上)手机开启拍照功能,既要申请CAMERA 权限,还要申请 WRITE_EXTERNAL_STORAGE 权限。
    1. Android 7.0(API24)以及以上版本不支持file://这种类型的URI,而是使用content://这种类型的URI。不然会报android.os.FileUriExposedException这个错,使用Android 7.0(及以上)手机拍照功能时,一定要注意这个api的变化。
    1. 使用Android 8.0(及以上)手机更新安装apk时,在Mainfest.xml 中请求安装权限android.permission.REQUEST_INSTALL_PACKAGES

5、华为手机app闪退重启清空log日志问题

解决方案:

◆ 方式1(最全面的解决方案):

找到手机设置 ---> 最后的开发人员选项 ---> 在调试模块,打开USB调试。 
还是调试模块内,找到日志记录器缓冲区大小,改为1M(也可选择更大),
然后进入拨号界面输入:*#*#2846579#*#*  ----> 选择USB端口设置 ----> 选择Google模式。

◆ 方式2:拨号键盘 + 快捷键设置(这种方式不是所有log都能显示)

进入拨号界面输入:*#*#2846579#*#*
依次选择:后台设置 ---> LOG设置 ---> AP 日志,重新启动手机。

◆ 方式3:错误出现后,迅速拔掉USB线,这是一个拼手速的方法,成功率不敢保证。


6、关于华为手机App权限更改导致应用重启的坑(暂且我还没有很好的解决方式)

问题重现:

  • 1.当我们在华为手机上打开一个应用,将应用退至后台进程中。
  • 2.打开 “设置”去更改该应用的权限(比如将“存储”权限由授权状态改为非授权状态)。
  • 3.再将该应用重新切换到前台,会发现应用进行了重新启动。 (在该app中,启动的时候,FragmentManager仍然会持有原有的fragment。)

网上有人说出了一种原因和一种 解决方案:当应用的权限发生变化的时候,华为手机发出广播,导致应用重新启动。 解决办法(比较笨):在Activity的onCreate()方法中,根据FragmentManager获取到已经存在的fragment,并将它们移除掉。重新再创建一下需要展示的fragment

但是我想知道framework层是如何操作的?不知道有没有大佬能够分析一下源码?


(三)魅族

(1)文档

魅族开发者文档


(四)oppo

(1)文档

oppo开发者文档

(2)问题

2、关于开发者选项

oppo手机的开发者模式很恶心,开启“设置”》其他设置》开发者选项》USB调试 待机,然后状态栏有个黄色的提醒窗口,提示10分钟后自动关闭开发者选项。

3、关于验证码

装个应用要验证码,打开开发者选项需要验证码。。很恶心。。

4、oppo手机的R9系列和A系列的5.1系统存在严重的bug,类似以下这种的gc导致的释放超时很多。

(五)vivo

(1)文档

vivo开发者文档

(2)问题

  • 关于as项目无法在vivo中安装的问题:

最近适配vivo手机 用的是vivo x9 发现应用无法在手机上安装 已经打开了开发者模式还是不行,报以下错:

【解决方案】
关掉Android Studio的Instant Run功能,然后把开发者模式中的USB安全模式(在USB调试下面)和USB调试一起打开。(其他手机遇到同样问题,也可以用这个方式解决。)


(六)锤子

(1)文档

暂且没找到相关文档。。。


二、开发中遇到的问题在不同手机上的处理方式

(一)沉浸式状态栏适配

  • 这里讲一下华为手机沉浸式状态栏和虚拟键盘冲突问题怎么解决:

由于字数限制,详细代码请看我的github https://github.com/AweiLoveAndroid/Solve-StatusBar-VirtualKeyBoard

(二)沉浸式状态栏图标的适配

  • 2.2.1 小米MIUI系统适配

之前做沉浸式状态栏,由于公司APP底色是白色,所以对MIUI进行特殊处理。在MIUI V6及以上版本,调用MIUI的方法将状态栏图标改为黑色。发现部分小米手机,这样的设置不管用,导致头上一片白,状态栏上的东西基本看不到。

调整过程中发现以下情况:

手机型号 MIUI版本 Android版本 系统方法是否生效 MIUI的方法是否生效
红米 NOTE 1LTE MIUI 8 8.2.1稳定版 4.4 生效
小米5 MIUI 8 8.5.3稳定版 7.0 生效
MI 3W MIUI 9 7.9.14开发版 6.0.1 生效

参考官方文档: http://www.miui.com/thread-8946673-1-1.html

(三)应用卸载然后安装更新的适配

  • 2.3.1 华为适配
    华为手机程序卸载,安装更新包,还是提醒更新包与安装应用签名不一致。

  • 2.3.2 魅族适配

    • 问题1. 测试的签名和你正式出包的签名如果不一致就不能安装,卸载应用也没用。
    • 问题2. 用as安装过应用,卸载后安装正式的apk就安装不了,用adb命令卸载后就行了。

(四)改变状态栏字体颜色为黑色的适配

  • 2.4.1 小米适配
/**
 * 改变小米的状态栏字体颜色为黑色,要求MIUI6以上
 * tested on: MIUI V7 5.0 Redmi-Note3
 */
private void processMIUI(boolean lightStatusBar) throws Exception{
    Window window = getWindow();
    Class<? extends Window> clazz = window.getClass();
    int darkModeFlag;
    Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
    Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
    darkModeFlag = field.getInt(layoutParams);
    Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
    extraFlagField.invoke(window,lightStatusBar ? darkModeFlag : 0, darkModeFlag);
}
  • 2.4.2 魅族适配
/**
 * 改变魅族的状态栏字体为黑色,要求FlyMe4以上
 */
private void processFlyMe(boolean isLightStatusBar) throws Exception{
    Window window = getWindow();
    WindowManager.LayoutParams layoutParams = window.getAttributes();
    Class<?> instance = Class.forName("android.view.MiuiWindowManager$LayoutParams");
    int value = instance.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON").getInt(layoutParams);
    Field field = instance.getDeclaredField("meizuFlags");
    field.setAccessible(true);
    int origin = field.getInt(layoutParams);
    if(isLightStatusBar){
        field.set(layoutParams, origin | value);
    }else{
        field.set(layoutParams, -value | origin);
    }

}

下面来一张示例图:

(五)屏幕圆角实现和适配

示例图
  • 实现原理:利用WindowManager将我们的圆角加到屏幕的四个角,圆角颜色设置为黑色,形成视觉圆角屏幕。

下面简单的把一些核心代码讲一下:

  • 自定义圆角View,这里以左上角为例:
// top left
case Gravity.TOP | Gravity.LEFT:
    path.moveTo(0.0f, 0.0f);
    path.lineTo(0.0f, (float) h);
    path.arcTo(new RectF(0.0f, 0.0f,
            ((float) w) * 2.0f, ((float) h) * 2.0f), 180.0f, 90.0f, true);
    path.lineTo((float) w, 0.0f);
    path.lineTo(0.0f, 0.0f);
    path.close();
    break;
  • windowmanager在添加view的时候需要设置一个WindowManager.LayoutParams。下面初始化这个Params:
// window manager
manager = (WindowManager) this.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams();
/*
 系统提示类型:7.0以前可以直接用TOAST的类型,不用申请权限,直接添加
 7.0以后不行了,需要申请SYSTEM_ALERT_WINDOW权限,window type最好
 设置为ERROR 或者 PHONE
 */
if (Utilities.isCanUseToastType()) {
    params.type = WindowManager.LayoutParams.TYPE_TOAST;
} else {
    params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
}
params.format = 1;
params.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN // 全屏
        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS // 覆盖到status bar
        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION // 覆盖到导航栏

        // 以下属性设置加载我们圆角window 不抢焦点,不拦截事件
        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
params.alpha = 1.0f;
params.x = 0;
params.y = 0;
// 设置  大小为全屏
params.width = ViewUtil.getScreenSize(this).x;
params.height = ViewUtil.getScreenSize(this).y;


  • 圆角加到屏幕上:
public void addCornerViewByPosition(String position){
    boolean enable = true;
    switch (position) {
        case LEFT_TOP:
            enable = leftTopEnable;
            params.gravity = Gravity.TOP | Gravity.LEFT;
            break;
        case RIGHT_TOP:
            enable = rightTopEnable;
            params.gravity = Gravity.TOP | Gravity.RIGHT;
            break;
        case LEFT_BOTTOM:
            enable = leftBottomEnable;
            params.gravity = Gravity.BOTTOM | Gravity.LEFT;
            break;
        case RIGHT_BOTTOM:
            enable = rightBottomEnable;
            params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
            break;
    }
    CornerView corner = buildCorner(enable,params.gravity);
    if(!corners.containsValue(corner)) {
        corners.put(position, corner);
        manager.addView(corner, params);
    }
}

屏幕圆角实现和适配,详细的可以点击这里:http://mp.weixin.qq.com/s/h5qRvfgVj04f_xExTtrIHg

(六)在带虚拟按键的手机上,虚拟按键会遮挡全屏图片的底部的解决。

在做splash页面的时候,通过windowBackground设置背景图片,在带虚拟按键的手机上,虚拟按键会遮挡图片的底部,这个问题的解决方式:

参考:http://blog.csdn.net/c15522627353/article/details/52452490

究竟如何适配Android底部虚拟按键,可以参考这篇博文:https://www.jianshu.com/p/b499628e0ae0

(七)悬浮窗权限设置了,dialog还是不提示。

(八)在Nexus 手机,原生Android 8.0上,使用扫码的时候显示的拍照预览方向不正,有180度的旋转并且变形的,解决方案:

private void surfaceIsChanged() {
    if (mHolder.getSurface() == null) {
        System.out.println("getSurface,nullnull");
        return;
    }
    try {
        mCamera.stopPreview();
    } catch (Exception e) {
        e.printStackTrace(); 
    }
    try {
        Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
        int dataBufferSize = (int) (previewSize.height * previewSize.width
              * (ImageFormat.getBitsPerPixel(mCamera.getParameters()
             .getPreviewFormat()) / 8.0));
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.setPreviewDisplay(mHolder);
        mCamera.setPreviewCallback(previewCallback);
        mCamera.startPreview();
        mCamera.autoFocus(autoFocusCallback);
        
        // 核心代码:根据照相的内容进行设置显示方向。
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        // DO your logic to get front or back camera...or loop through all avaialable.
        int camIdx = 0; 
        Camera.getCameraInfo(camIdx, cameraInfo);

        try {
            // If using back camera then simply rotate what CameraInfo tells you.
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK){
                mCamera.setDisplayOrientation(cameraInfo.orientation);
            }else{
                // If using front camera note that image might be flipped
                //  to give users the impresion the are looking at a mirror.
                mCamera.setDisplayOrientation( (360 - cameraInfo.orientation) % 360);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //开始扫描
        // Toast.makeText(QRZbarActivity.this, "开始扫描",Toast.LENGTH_SHORT).show(); 
        // 打开闪光灯,这个方法自己去实现,这里不是重点,就不写了。
        autoOpenLight();
    } catch (Exception e) {
        Toast.makeText(BaseScanActivity.this, R.string.account_toast_not_open_camera, 
                   Toast.LENGTH_SHORT).show();
        // showTip("您未允许" + getResources().getString(R.string.app_name) 
        // + "访问您的相册\n请在“安全中心 -授权管理”中更改设置");
        Log.d("DBG", "Error starting camera preview: " + e.getMessage());
    }
}

这个解决方案来自:https://stackoverflow.com/questions/12017148/android-camera-setdisplayorientation90-fails-in-different-devices#


(九)获取手机里所有存储设备盘符,不同厂商手机的路径可能不一样。

问题描述:华为手机很变态,存储路径跟原生系统的不一样,所以需要对其做特别处理。

解决方案: 需要用到一个被系统隐藏的方法,即StorageManager下的getVolumePaths()方法。具体通过反射可以得到,其中mPath、mRemovable、mEmulated、mState这几个属性是我们需要关注的。

具体代码:

public class StorageUtils {
    /*
    获取全部存储设备信息封装对象
     */
    public static ArrayList<Volume> getVolume(Context context) {
        ArrayList<Volume> list_storagevolume = new ArrayList<Volume>();

        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);

        try {
            Method method_volumeList = StorageManager.class.getMethod("getVolumeList");

            method_volumeList.setAccessible(true);

            Object[] volumeList = (Object[]) method_volumeList.invoke(storageManager);
            if (volumeList != null) {
                Volume volume;
                for (int i = 0; i < volumeList.length; i++) {
                    try {
                        volume = new Volume();
                        volume.setPath((String) volumeList[i].getClass().getMethod("getPath").invoke(volumeList[i]));
                        volume.setRemovable((boolean) volumeList[i].getClass().getMethod("isRemovable").invoke(volumeList[i]));
                        volume.setState((String) volumeList[i].getClass().getMethod("getState").invoke(volumeList[i]));
                        list_storagevolume.add(volume);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    }

                }
            } else {
                Log.e("null", "null-------------------------------------");
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        return list_storagevolume;
    }


    /*
     存储设备信息封装类
     */
    public static class Volume {
        protected String path;
        protected boolean removable;
        protected String state;

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public boolean isRemovable() {
            return removable;
        }

        public void setRemovable(boolean removable) {
            this.removable = removable;
        }

        public String getState() {
            return state;
        }

        public void setState(String state) {
            this.state = state;
        }
    }
}

测试代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ArrayList<StorageUtils.Volume> list_volume = StorageUtils.getVolume(this);
        for (int i=0;i<list_volume.size();i++){
            Log.e(i+"","path:"+list_volume.get(i).getPath()+"----"+
                        "removable:"+list_volume.get(i).isRemovable()+"---"+
                        "state:"+list_volume.get(i).getState());
        }
    }
}

需要添加权限:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>


本文部分内容引用了该博客: https://www.jianshu.com/p/7609d5a62c45


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,825评论 25 707
  • 本文章转载于搜狗测试 Android应用适配测试浅谈 什么是Android适配测试 Android适配测试是为了让...
    夜境阅读 1,354评论 0 1
  • 数据库分类: 关系型数据库 关系数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库...
    夜幕繁华阅读 514评论 0 1
  • 什么是异步编程 什么是异步编程呢?举个简单的例子: 上面这段代码中,Main方法中的代码是按照自上而下的顺序执行的...
    雪飞鸿阅读 4,407评论 0 12
  • 1.《想你》 夜深人静时, 我想起你, 内心独白了一遍又一遍。 2.《39.4》 39.4度, 一个好厉害的温度,...
    无语呤咽阅读 381评论 2 4