小米开发平台小米妙播适配说明

小米开发平台小米妙播适配说明

一、小米妙播背景与介绍

1.1 安卓原生Media Session介绍

Android 框架定义了两个类(媒体会话和媒体控制器),它们为构建媒体播放器应用提供了一个完善的结构。

媒体会话和媒体控制器通过以下方式相互通信:使用与标准播放器操作(播放、暂停、停止等)相对应的预定义回调,以及用于定义应用独有的特殊行为的可扩展自定义调用。

更多信息详见:https://developer.android.com/guide/topics/media-apps/media-apps-overview

1.2 MIUI小米妙播介绍

小米妙播支持基于Media Session的音频播控、基于Wi-Fi的跨设备音乐接力。

用户可以在小米手机和平板的系统控制中心、通知栏/锁屏媒体中心使用该功能。

控制中心内的小米妙播播控,基于安卓原生Media Session能力实现,音频应用适配Media Session即可,众多知名三方应用均已适配。

二、适配小米妙播的好处

2.1 系统全局常驻播控

小米妙播作为控制中心常驻的播控、互联入口,用户可以在手机全局操作音频,是Android厂商中全面媲美苹果 AirPlay2 的系统级功能。

2.2 覆盖更多场景的播放

各音频app的用户活跃场景不再局限于手机,用户用音箱等设备听歌时,也可使用各音频app,通过小米妙播互联播放。

三、适配方式

基本适配方式请参考谷歌官方文档:

https://developer.android.com/guide/topics/media-apps/working-with-a-media-session

https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice

适配要点:

及时更新Meta信息

// 构建MediaSession
MediaSessionCompat mMediaSession;
//构建MediaMetadata,并传入媒体meta信息(歌曲名、专辑名、歌手名、歌曲时长等)
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, getTrackName())
        .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, getAlbumName())
        .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, getArtistName())
        .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration());
MediaMetadataCompat metadata = builder.build();
mMediaSession.setMetadata(metadata);
// 构建并传入歌曲封面
Bitmap result;
// 获取封面BitMap...
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, result);
mMediaSession.setMetadata(builder.build());

及时更新播放状态信息

// 构建PlaybackState,传入播放状态、播放进度等信息。
PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(getSourcePlaybackState())
        .setBufferedPosition(getBufferedPosition())
        .setState(PlaybackStateCompat.STATE_PLAYING, position(), getSpeedRatio());
mMediaSession.setPlaybackState(builder.build());

处理播放回调 

// 构建MediaSessionCompat.Callback回调,处理播放、暂停、上一首、下一首、调整播放进度等操作
private class MediaPlaybackSessionCallback extends MediaSessionCompat.Callback {
    @Override
    public void onPlay() {
        play();
    }
    @Override
    public void onPause() {
        pause();
    }
    @Override
    public void onSkipToNext() {
        next();
    }
    @Override
    public void onSkipToPrevious() {
        prev();
    }
    @Override
    public void onFastForward() {
        forward();
    }
    @Override
    public void onRewind() {
        backward();
    }
    @Override
    public void onStop() {
        stop();
    }
    @Override
    public void onSeekTo(long pos) {
        seek(pos);
    }
}
mMediaSession.setCallback(new MediaPlaybackSessionCallback());

小米分屏功能适配说明

小米分屏功能适配说明

1. 前言

从 7.0 开始,Android 加入了新的特性 Multi-Window,以支持同时显示多个应用,根据不同场景及设备,细分为以下三种:

  • Split-Screen Mode,即分屏,用于手机和平板
  • Picture-in-Picture Mode,即画中画,用于电视端(Android N)及移动端(Android O)
  • Freeform Mode,自由模式,用于在更大尺寸的设备上自由缩放应用窗口

可以看到,分屏是 Multi-Window Mode 的其中一种,用于手机等移动设备。MIUI 从 MIUI 9 开始支持分屏,基于 Android 7.0 优化,因此开发者不用针对 MIUI 做重复的适配工作。

2. MIUI 分屏的表现

  • 默认将窗口一分二,支持调整窗口大小。
  • 支持横屏
  • 支持主应用始终在前台
  • 对于折叠屏设备,在屏幕展开状态下,分屏模式为左右分屏,而且宽度支持多档位调节

3. 分屏对开发者的好处是

如前所述,Android 7.0 的分屏允许某个应用始终可见,MIUI 会在这个基础上做更多的交互优化,以符合用户的预期。在这个背景下,分屏对于开发者来说有以下好处:

  • 可能提升使用时长:由于应用始终可见,主流程不会被打断,有助于提升使用时长。
  • 可能提升日均使用次数:使用分屏后,消费长内容(如长视频)的成本变低了,用户不用想着留一整段时间,也有助于提升使用次数。

随着 Android 7.0 的设备越来越多,支持分屏带来的好处将会被不断放大。加之 Android 有标准的分屏接口,大大减少了开发者的适配工作量。

4. 如何支持分屏

支持分屏的方式非常简单,只需要声明一个属性。从 7.0 开始,Android 新增了一个 Activity 属性: resizeableActivity ,以声明该 Activity 是否支持多窗口显示。

android:resizeableActivity=["true" | "false"]

如果这个属性设为 true ,Activity 就可以在分屏模式下显示;设为 false ,Activity 则不会在分屏模式下显示,而是会占满整个屏幕。因此开发者可以根据具体场景,仅让部分 Activity 支持分屏。

若开发者没有为 Activity 声明该属性,Android 会根据应用的 targetSDKVersion 及 Activity 的 screenOrientation 属性来综合判断是否可以在分屏显示。关于判断的详细逻辑,可以参考官方文档 Configuring Your App for Multi-Window Mode 或者这篇更详细的博客 Android N7.0多窗口适配开发指导 。

5. 如何进一步优化分屏模式

配置 resizeableActivity 的属性,是适配分屏的最简单方式,但如果想要提供更好的使用体验,需要开发者做一定优化工作。下面是我们了解到的一些案例(测试机型:Nexus 6 Andriod 7.1),开发者可以根据自己的业务需求,做不同程度的优化。

5.1. 减少不可滑动的页面/控件

在分屏过程中,屏幕高度只有原来的一半,如果有太多的控件不响应滑动事件,那么用户将无法上下滚动应用页面,甚至无法进行下一步操作。这类页面,最常见于Splash screen、登录注册页、音乐播放页、大图区域、弹窗等。

由于用户可以自由调整分屏的窗口比例,因此开发者只要减少了不可滑动的控件,分屏的可用性就会大大提高,是性价比非常高的优化方案。

5.2. 尽可能使用相对位置,以兼容多种窗口尺寸

分屏时,屏幕的高度和宽度会发生变化,因此在书写控件布局时,尽量使用相对位置,以避免窗口大小改变时,控件无法显示或显示不全。这也是一种性价比很高的优化方案,可以保证用户在分屏时能正常使用应用。

5.3. 注意多窗口下 Activity 的生命周期

视频、直播等类别的应用需要特别关注这一点。Android 7.0 在分屏时会同时运行两个应用,其中用户最后操作的那个应用会处于 Resumed 状态,另一个则会处于 Paused 状态。

这会带来一些问题,以视频应用为例,如果开发者在 onPaused 中处理视频的 「暂停/播放」,那在分屏时,就会因为用户操作另一个应用,导致视频停止播放。因此我们建议开发者在 onStart/onStop 中处理视频的「暂停/播放」,或者特殊处理分屏时的 Paused 状态。详见官方文档 Multi-Window Lifecycle

5.4. 处理 Configuration Changes

由于分屏过程中,允许用户调整窗口的大小,这就会导致 Configuration 的改变。Android 的默认处理方式是 relaunch 整个 Activity,从而出现页面闪一下的问题。如果想避免闪一下的问题,建议开发者自己处理 Configuration 的变化。

5.5. 给内容更多空间

分屏后,屏幕空间变得非常小了,为了给内容让出更多空间,应尽量减少常驻控件。一种解决办法是在浏览内容时,隐藏底部tab等常驻控件,用户回滚时再出现,以展示更多的内容。

5.6. 为分屏定制新的布局(动态布局)

动态布局指根据当前的窗口大小,重新调整页面的布局。这是一项锦上添花的优化项,开发者可以酌情考虑是否添加此优化。

6.FAQ

6.1. MIUI 分屏支持哪些设备

搭载 Android 7.0 或以上的 MIUI 手机及平板设备均支持分屏。MIUI 也将尝试将分屏移植至 Android 6.0。因此将有数千万的新老设备支持分屏。

6.2. 如何调试

MIUI 的分屏方案完全兼容 Android 7.0,因此可以在任意运行 Android 7.x 的设备上调试,无需为 MIUI 作特别处理。同时,以上提到的案例均能在任意 Android 7.x 设备复现。调试过程中,建议开启以下设置项:「开发者选项 > 强制将活动设为可调整大小」,然后重启手机,之后系统就会强制应用进入分屏模式,以方便开发者观察应用在分屏时的表现。

6.3. 分屏是个伪需求吗,用户为什么需要分屏

分屏不仅不是伪需求,而且会是一个大众需求。我们认为分屏最主流的使用场景是:一边看视频,一边做其它事情。用手机看视频,已经成为用户的主流场景,各大视频应用的日活人数、使用次数、使用时长都可以佐证这个观点。但使用手机看视频有很多痛点,比如会被 IM 消息打断、切换至后台视频会暂停等。这些痛点都可以通过分屏较好地解决,这也是分屏能成为大众需求的潜力。

但不可否认的是,分屏也会带来很多可用性问题,尽管系统已经做了很多优化工作,仍然需要各大开发者做进一步的优化,提高分屏模式的可用性。因此非常希望各位开发者能够支持该功能,为广大用户提供更好的使用体验。再次感谢所有开发者的支持与付出!

6.4. 参考资料

小米MIUI小部件技术规范与系统能力说明

MIUI Widget 数据恢复适配

5.1.描述

Android 系统提供了 onRestored 方法用于数据从云端备份恢复时的 Widget 配置迁移。在此基础之上,MIUI Widget 新增了一个 Widget 配置迁移的时机。开发者无需关心何时回调,只需将新的WidgetId与数据绑定并更新UI。

注意:当 MIUI Widget 卡片有配置信息且存在多张卡片的配置信息不一致时需要进行相应适配(例如股票卡片,用户可以添加多张卡片,且每张卡片展示不同的股票),其他情况无需适配。

5.2.示例

public class ExampleWidgetProvider extends AppWidgetProvider {
  @Override
  public void onRestored(Context context, int[] oldWidgetIds, int[] 
    newWidgetIds) {
       super.onRestored(context, oldWidgetIds, newWidgetIds);
       onIdRemap(oldWidgetIds, newWidgetIds, null);
    }

   @Override
   public void onAppWidgetOptionsChanged(Context context, AppWidgetManager
     appWidgetManager, int appWidgetId, Bundle newOptions) {
         super.onAppWidgetOptionsChanged(context, appWidgetManager, 
         appWidgetId, newOptions);
         // MIUI Widget 新增配置迁移时机
         if (newOptions.getBoolean("miuiIdChanged") &&  
                !newOptions.getBoolean("miuiIdChangedComplete")) {
             onIdRemap(newOptions.getIntArray("miuiOldIds"),
             newOptions.getIntArray("miuiNewIds"), newOptions);              
         }
    }

    private void onIdRemap(int[] oldWidgetIds, int[] newWidgetIds, Bundle options) {
        int length = oldWidgetIds.length;
        for (int i = 0; i < length; i++) {   
            int newWidgetId= newWidgetIds[i];
            RemoteViews views = new RemoteViews(context.getPackageName(),    
            R.layout.appwidget_provider_layout);
            //开发者进行数据迁移,并完成新的数据获取
            ...
            //以上操作完成后,先调用updateOptions,再调用updateAppWidget
            if(options != null) {
                //这一步必须执行
                options.putBoolean("miuiIdChangedComplete", true);                             
    AppWidgetManager.getInstance(context)
                .updateAppWidgetOptions(newWidgetId, options);
            }
            AppWidgetManager.getInstance(context)
            .updateAppWidget(newWidgetId, views);
        }
    }
}

6.页面跳转规范

6.1.描述

点击MIUI Widget 跳转应用页面时,推荐使用 PendingIntent 设置相应的 Activity 进行跳转。若业务有分发逻辑可以使用Activity进行中转。

不建议使用PendingIntent 启动BroadcastReceiver/Service,然后在BroadcastReceiver/Service里面启动 Activity。

6.2.示例

// step1: 构建跳转页面的 PendingIntent
Intent intent = new Intent(context, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// step2: 生成 RemoteViews 关联 PendingIntent
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
// step3: 关联 widget 和 RemoteViews
appWidgetManager.updateAppWidget(appWidgetId, views);

7.MIUI Widget 布局规范

7.1.描述

系统通过固定的ID找到相应控件并添加圆角,保证所有MIUI Widget圆角统一。因此开发者需要在小部件的根布局上声明ID为”@android:id/background”。由于MIUI Widget 切换页面的动画使用到了背景色,因此根布局

必须有背景色且不能为全透明

7.2.示例

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ... 
    // 颜色值为示例
    android:background="#fff"
    android:id="@android:id/background">
    ...
</LinearLayout>

8.MIUI Widget 布局兼容适配

8.1.描述

为了让用户有更好的体验,MIUI Widget 需要保证以下场景正常显示:

  • 负一屏、默认布局下的桌面正常显示
  • 桌面图标行列数变化后正常显示 需保证桌面4×6、5×6网格体系都能正常显示(设置方式:设置—桌面—桌面布局)
  • 桌面搜索框变化时正常显示 需保证有搜索框、无搜索框都能正常显示(设置方式:设置—桌面—桌面搜索框)
  • 桌面虚拟键变化时正常显示 需保证有虚拟键、无虚拟键都能正常显示(设置方式:设置—桌面—系统导航方式)
  • 1k、2k屏幕手机都能正常显示

为了使卡片在各种场景下都有较好的展现,需要做以下适配:

  • MIUI Widget 根布局宽高必须使用match_parent, 内容区需要在根布局里居中
  • 内容区控件尽量不要使用绝对尺寸和绝对位置,可以使用RelativeLayout以及LinearLayout的layout_weight等控制控件的位置和尺寸

8.2.示例

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/background"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    <!--widget_root_padding 与设计图保持一致,如示例图为40px-->
    android:padding="@dimen/widget_root_padding"
    android:gravity="center">

     <!--内容区-->
    <LinearLayout
        android:id="@+id/widget_content"
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:layout_height="match_parent">
    </LinearLayout>   
</FrameLayout>

9.应用清除数据适配

9.1.描述

用户在使用过程中可能存在清除应用数据的行为,用户清除数据时MIUI系统会给 MIUI Widget 发送刷新广播,此时应用处在无数据或未授权状态,开发者需要在该时机将小部件恢复成默认视图或授权视图。

9.2.示例

<receiver android:name="com.miui.ExampleWidgetProvider" >
    ...
    // MIUI Widget 标识
    <meta-data
    android:name="miuiWidget"
    android:value="true" />
    <intent-filter>   
        //MIUI展现刷新
        <action android:name="miui.appwidget.action.APPWIDGET_UPDATE" />    
    </intent-filter>
</receiver>

public class ExampleWidgetProvider extends AppWidgetProvider {
    ...
    @Override
    public void onReceive(Context context, Intent intent) {
        if ("miui.appwidget.action.APPWIDGET_UPDATE".equals(intent.getAction())) {
            int[] appWidgets = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
            // 根据应用自身逻辑更新视图 
            ...
        } else {
            super.onReceive(context, intent);
        }
    }
}

10.小部件版本号

10.1.描述

MIUI小部件增加版本号,方便小部件版本迭代管理。小部件版本号针对应用内所有小部件,而非单个。当应用内任一小部件发生功能变动或新增小部件时需升级小部件版本号。若小部件较前一应用版本未发生变动,则无需更改小部件版本号。

注意:

  • 名称为”miuiWidgetVersion” 的meta-data标签,应放置在application下而不是某个小部件provider下。
  • 小部件发生变动或新增时一定要修改小部件版本,否则存在应用所有小部件被下线的风险。
  • 小部件版本号为整数,从1开始,同应用版本号的升级一致,都只能升高。

10.2.示例

AndroidManifest.xml 文件参考如下配置:

<application
...
<meta-data
    android:name="miuiWidgetVersion"
    android:value="1" />
...
</application>

11.MIUI Widget 大屏适配

11.1.描述

为了使MIUI Widget可以在大屏设备(折叠屏,平板)上提供更好的用户体验,需要对MIUI Widget在大屏幕设备上进行适配。

11.2.编辑页适配

若开发者在MIUI Widget中设置了编辑页,大屏设备上适配后的展示效果如下图所示:

适配方法:

  • 对于小部件视图树上,所有可以通过点击调起编辑页面的视图控件,需要在代码中进行以下调用:
public class ExampleWidgetProvider extends AppWidgetProvider {
    ...
    @Override
    public void onUpdate(Context context, AppWidgetManager 
        appWidgetManager, int[] appWidgetIds) {
        for (int appWidgetId : appWidgetIds) {          
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_ui);
            // 编辑页适配
            val widgetOptions = AppWidgetManager.getInstance(context).getAppWidgetOptions(appWidgetId)
            //由host提供,业务直接读取,以判断当前设备是否支持大屏预览模式
            if (widgetOptions != null && widgetOptions.getBoolean("miuiLargeScreenDevice", false)) {
                //如果当前设备支持大屏预览模式,则先生成一个Bundle实例,再分别执行步骤1,2
                val largeScreenOptions = Bundle().apply {
                    //1. 传入widgetId
                    putInt("miuiWidgetId", widgetId)                                      
                }
                //2. 通过setBundle方法,调用控件的supportLargeScreenEditPreviewMode方法,并传入以上生成的Bundle
                //R.id.item_container_1 为一个示例,所有点击事件为调起编辑页的控件,都必须进行类似的调用
                remoteViews.setBundle(R.id.item_container_1, "supportLargeScreenEditPreviewMode", largeScreenOptions)
            }    
            appWidgetManager.updateAppWidget(widgetId, views);
        }
        ....
    }
}
  • 如果业务小部件有长按编辑入口,则在生成编辑页面链接时,需要新增miuiWidgetId参数:
//示例:
public class ExampleWidgetProvider extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager 
        appWidgetManager, int[] appWidgetIds) {
        for (int appWidgetId : appWidgetIds) {          
            Bundle options =   
            appWidgetManager.getAppWidgetOptions(appWidgetId);
            String path = 
            "widgetdemo://com.miui.widgetdemo/widget/WidgetEditActivity";
            Uri.Build uriPath = Uri.parse(path).buildUpon();
            //本次新增参数,host依据此参数来判断,业务编辑页是否支持大屏预览模式
            uriPath.appendQueryParameter("miuiWidgetId", widgetId.toString());
            options.putString("miuiEditUri", uriPath);
            appWidgetManager.updateAppWidgetOptions(appWidgetId, options);
            RemoteViews views =   
            new RemoteViews(context.getPackageName(), 
            R.layout.widget_ui);
            appWidgetManager.updateAppWidget(widgetId, views);
        }
        ....
    }
}
  • 业务侧在编辑页面Activity的onCreate方法中,需要从Intent中解析对应参数,判断是否以大屏预览模式展示,并对大屏预览模式下的编辑页面进行改造:
public class WidgetEditActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        val intent = getIntent()
        //是否以大屏预览模式展示
        if (intent.getBooleanExtra("isLargeScreenMode", false)) {
            //该字段返回一个矩形区域,代表小部件在屏幕坐标系上的具体位置
            val rect = intent.getParcelableExtra("miuiWidgetScreenBound")
            if (rect != null) {
                //业务需要根据rect提供的小部件位置信息,来计算业务内容视图的具体展示位置:
                //1、业务内容视图应当始终展示在小部件的左侧,或者右侧,距离小部件固定间距
                //2、业务内容视图应当在小部件的左侧和右侧中,选择空间较大的一侧展示
            }
        }
    }
}

需要注意的事项:

  • 不要在生成PendingIntent时,put自定义的Parcelable对象或者Serializable对象,这样会导致Host处理intent时因找不到类而抛异常。请转换成基础数据类型进行传递。
  • 请不要在生成PendingIntent时,添加FLAG_IMMUTABLE,否则业务将无法解析到Host添加的参数,android s以上可以换成FLAG_MUTABLE。
  • 编辑页面打开时,不允许横竖屏旋转(需要支持横竖屏,只是不允许动态旋转)。
  • 业务只需要负责编辑页面内容区域(如上图示中的白色背景覆盖区域)的展示,背景高斯以及小部件的预览图部分,均由Host实现。

11.3.布局适配

在大屏设备上,负一屏和桌面对业务小部件布局进行了全局缩放,因此一般情况下,不需要业务再对小部件进行额外适配。

如果业务希望自行对小部件进行更完美,精细的适配,可以选择将全局缩放能力关闭,只需要在小部件对应的provider里,加上如下所示的配置即可

<receiver
    android:name=".service.normal.widget.NormalExampleWidgetProvider">
    <meta-data
        android:name="miuiAutoScale"
        android:value="false"/>
</receiver>

提示: 对于使用了GridView或者ListView的小部件,该方法不能使用,如遇到问题,请联系相关技术支持。

12.注意事项

12.1.圆角

MIUI Widget 虽然会在MIUI13上统一裁切圆角,但为了能够兼容旧版系统和非MIUI 手机,开发者仍需为MIUI Widget添加圆角 ,圆角大小与设计规范保持一致。

12.2.刷新兼容

曝光刷新仅存在支持MIUI Widget的系统中(可通过“MIUI 小部件系统能力说明–是否支持MIUI Widget”判断),在不支持MIUI Widget 的系统以及非MIUI手机上,MIUI Widget刷新机制与原生Widget保持一致,各项目需要根据原生刷新机制以及业务需求进行适配。

12.3.Activity 进程

系统会对 Widget 进程进行优化,系统资源紧张时,Widget 进程容易被回收。为了保证 Activity 的正常显示,Activity所在进程不能是Widget 进程

12.4.小部件名称

MIUI Widget必须配置小部件名称。开发者可以根据每个小部件的功能,为小部件撰写一个简洁的名字(2~8个汉字),帮助用户理解小部件的用途。在小部件中心里,小部件名称会展示为“应用名称·小部件名称”,为了展示体验更佳,小部件名称与应用名称不得相同。小部件名称对应代码AndroidManifest.xml中receiver的label。设置方法如下:

<receiver
    android:name="com.miui.widgetdemo.provider.ExampleWidgetProvider"
    android:label="@string/app_widget_example"
    android:process=":widgetProvider">
    ...
</receiver>    

12.5.深色模式

MIUI Widget 只能在xml中静态适配深色模式(通过配置drawable-night、values-night等资源文件适配),不支持在RemoteViews通过代码动态设置深色模式。

12.6.禁止随意修改 MIUI Widget的receiver类名

Android系统会根据receiver类名标识 MIUI Widget。一旦改名,用户在旧版添加的小部件升级后就会消失。因此 MIUI Widget 一旦审核通过,禁止随意修改receiver类名。

12.7.小部件通过审核后,禁止随意移除 MIUI Widget 标识

通过审核的小部件移除MIUI Widget 标识,会导致系统无法识别,造成一些严重的错误,因此小部件一旦审核通过,禁止随意移除MIUI Widget 标识。

小米手机 MIUI 10 通知样式及能力适配说明

小米手机 MIUI 10 通知样式及能力适配说明

MIUI 10 通知栏基于 Android O 做了重构,大大增强了通知栏的能力,分别是:

  • 支持 6 种通知样式
  • 支持 Large icon
  • 支持 Actions
  • 支持快捷回复 (Direct reply) 

1. 前言

  • 以下图片,仅用于示意,线上效果可能会有变化,请在最新 MIUI 版本中测试样式及逻辑。
  • 以下图片示例的都是 MIUI 10 国内版的效果,国际版的布局将会沿用原生 Android 的样式。
  • 以下特性,全部需要开发者自行适配。通知栏只是提供基础能力, 但是否使用由开发者决定。
  • 以下提及的接口均为 Android 标准接口,可在官方文档中查询,但也要注意是从哪个 Android 版本开始支持。
  • 对于使用推送通道的开发者,需要确认相关推送通道是否支持以下能力及相关标准接口,若不支持,则无法使用相关能力。

2. 六种通知样式 (template)

原生 Android O 支持6种通知样式(或称 template),MIUI 10 也将完全兼容这些样式。

(关于原生 Android O 的通知样式介绍,详见 https://material.io/design/platform-guidance/android-notifications.html#templates )

2.1. 标准样式 (Standard template)

标准样式是最常见的样式,也是通知栏的默认样式,有以下特点:

  • 一般包含“标题”、“内容”、“图标”、“时间戳”4个元素
  • 一般无大视图

2.2. 大文本样式 (Big text template)

自 API 16 (Android 4.1) 引入,用以展示更多的文本内容,有以下特点:

  • 有标准视图 (standard view),看起来与标准样式 (Standard template) 一样。
  • 有大视图 (expanded view),有更大的面积,允许展示更多的内容。
  • 通过长按通知来切换标准视图和大视图。

代码示例:

Notification notif = new Notification.Builder(mContext)
   .setContentTitle("特斯拉召回两千余辆 ModelX")
   .setContentText("本次召回范围仅限部分车辆")
   .setSmallIcon(R.drawable.ic_phonelink_ring_primary_24dp)
   .setColor(ContextCompat.getColor(context, R.color.primary_light))
   .setPriority(Notification.PRIORITY_MAX)
   .setVibrate(new long[0])
   .setStyle(new Notification.BigTextStyle()
       .bigText("据上周美联社信息报道,特斯拉已宣布计划在全球范围内召回大约1.1万辆ModelXSUV,原因是后座可能无法锁定。"))
   .build();

该样式还有更多的接口供开发者使用,详见官方文档 https://developer.android.com/reference/android/app/Notification.BigTextStyle。

2.3. 大图样式 (Big picture template)

自 API 16 (Android 4.1) 引入,用以在通知里展示大图,适用于富媒体的内容:

  • 有标准视图 (standard view),看起来与标准样式 (Standard template) 一样。
  • 有大视图 (expanded view),支持展示一张大图,但无法与Big text template 共用,即无法展示长文本。
  • 通过长按通知来切换标准视图和大视图。

代码示例:

Notification notif = new Notification.Builder(mContext)
    .setContentTitle("Unsplash Curation")
    .setContentText("The best new high-res photos from Unsplash. Here’s a few of our team’s favourites from today.")
    .setSmallIcon(R.drawable.new_post)
    .setStyle(new Notification.BigPictureStyle()
        .bigPicture(aBigBitmap))
    .build();

更多的接口详见官方文档 https://developer.android.com/reference/android/app/Notification.BigPictureStyle

2.4. 进度条样式 (Progress template)

自 API 14 (Android 4.0) 引入,有以下特点:

  • 类型1:“无明确进度 (indeterminate)”,即无法预估结束时间,类似于 loading 动画。
  • 类型2:“有明确进度 (determinate)”,可以预估结束时间。
  • 支持标准视图 (standard view),类似标准样式加上了进度条。
  • 支持大视图 (expanded view),一般是展示按钮,如「取消」。
  • 进度条样式可以和 Big text、Big picture 混用(留待各位尝试)

代码示例:

代码层面上,Progress template 并不是一种 Style,无法通过 setStyle 来设置,而是通过 setProgress 来配置,因此才可以和 Big text、Big picture 混用。

以下是两种进度类型的代码示例:

#类型1:indeterminate
Notification notif = new Notification.Builder(mContext)
    .setContentTitle("正在下载安装包")
    .setContentText("即将更新至 MIUI 10")
    .setSmallIcon(R.drawable.ic_phonelink_ring_primary_24dp)
    .setProgress(100,50,true)
    .addAction(cancelAction)
    .build();
#类型2:determinate
Notification notif = new Notification.Builder(mContext)
    .setContentTitle("正在下载安装包")
    .setContentText("下载进度35%")
    .setSubText("还有27分钟")
    .setSmallIcon(R.drawable.ic_phonelink_ring_primary_24dp)
    .setProgress(100,35,false)
    .addAction(cancelAction)
    .build();

更详细的实现说明,也可以看官方文档 https://developer.android.com/training/notify-user/build-notification#progressbar。

2.5. 媒体样式 (Media template)

自 API 21 (Android 5.0) 引入,为音乐、广播等媒体播放设计的通知样式,详细介绍见这个文档 https://dev.mi.com/console/doc/detail?pId=1300 。

2.6. 对话样式 (Messaging template)

自 API 24 (Android 7.0) 引入,为对话式内容设计的通知样式,适用于 IM / 邮件等涉及会话的应用。有以下特点:

  • 支持单聊和群聊两种会话模式。
  • 支持普通视图 (standard view),类似标准样式。
  • 支持大视图 (expanded view),支持显示会话的上下文。

代码示例:

#类型1:单聊
Notification notif = new Notification.Builder()
    .setSmallIcon(R.drawable.ic_phonelink_ring_primary_24dp)
    .setLargeIcon(userAvatar)
    .setStyle(new MessagingStyle("我")
            .addMessage("爱乐之城怎么样", 1, "我")
            .addMessage("很不错啊,金球奖得主呢", 2, "韩梅梅")
            .addMessage("什么时候上映的?最近老在别的地方看到这个电影的介绍,被吊起胃口了", 3, "我")
            .addMessage("中国要情人节才上映", 4, "韩梅梅"))
    .addAction(replyAction)
    .build();
#类型2:群聊
Notification notif = new Notification.Builder()
    .setSmallIcon(R.drawable.ic_phonelink_ring_primary_24dp)
    .setLargeIcon(groupAvatar)
    .setStyle(new MessagingStyle("我")
        .setConversationTitle("这里是群聊名称")
        .addMessage("威少3节41分也是666", 1, "winson")
        .addMessage("落后好多咧", 2, "超")
        .addMessage("其他的不给力", 3, "winson")
        .addMessage("勇士赢是正常,但这不是一场普通的比赛了,大家都打出火气来了", 4, "我"))
    .addAction(replyAction)
    .build();

更多的接口详见官方文档 https://developer.android.com/reference/android/app/Notification.MessagingStyle

上面的例子,大家应该注意到 setLargeIcon 和 addAction 这两个方法,这是用来显示「用户头像」和「回复」按钮的方法。但这两个方法,不限于 Messaging template,可用于所有通知样式中,下面将仔细说明。

3. 支持 Large icon(测试性功能)

Android 通知默认没有 large icon,但开发者可以通过 setLargeIcon 方法 (自 API 11 – Android 3.0 引入) 给通知增加 large icon,丰富通知的内容,尤其适用于 IM / 邮件等场景。

自 MIUI 10 开始,MIUI 通知栏正式支持显示 large icon,示例效果如下。

代码示例:

Notification notif = new Notification.Builder()
    .setContentTitle("韩梅梅")
    .setContentText("中国要情人节才上映")
    .setSmallIcon(R.drawable.ic_chat_black_24dp)
    .setLargeIcon(userAvatar)
    .build();

未设置large icon时,会默认用应用桌面图标代替。有几点值得说明:

  • setLargeIcon 方法适用于所有通知样式,不限于上述例子。开发者可以配合 setStyle 方法,灵活搭配不同的样式。
  • MIUI 系统会自动在 large icon 的右下角添加应用 icon,以标示该通知的来源。因此不要把 large icon 设置为应用图标。
  • 请不要滥用 large icon,我们后续会视情况而定是否收紧这个能力。

4. 支持 Actions

Actions 指的是通知的快捷按钮,该特性自 API 16 (Android 4.1) 引入,并在 API 20 (Android 4.4W) 中更新。

在 MIUI 10,Actions 的样式如下(除媒体通知外,最多可以设置3个 Actions)。

有几点值得说明:

  • 默认不会有 Actions,需要开发者通过 addAction 主动声明。
  • 任何通知样式都可以添加 Actions(效果如下图),开发者可以自由搭配
  • Actions 只能在大视图时显示,在 MIUI 10,除了媒体通知,所有通知默认展示标准视图(标准视图不显示 Actions )。

5. 支持快捷回复 (Direct reply)

快捷回复 (Direct reply) 是 Android 7.0 引入的新功能,开发者适配后,可以支持在通知栏直接回复消息,而不用调起应用,示意图如下:

Direct reply 也不限通知样式(效果如下图),开发者可与不同的通知样式组合搭配。但 Direct reply 依赖于 Actions,因此需要先显示 Actions,才能触发 Direct reply。

关于 Direct reply 的实现方式,可以参考以下资料:

6. FAQ

6.1. 如何判断 MIUI 版本

有以下方法:

android.os.SystemProperties.get("ro.miui.ui.version.code", "7");// 如果返回值是「8」,就是 MIUI 10

android.os.SystemProperties.get("ro.miui.ui.version.name", "");// 如果返回值是「V10」,就是 MIUI 10

6.2. 如何测试

升级到  MIUI 10 最新开发版即可,支持的机型和下载链接如下:

小米手机MIUI 10 媒体通知适配说明

小米手机MIUI 10 媒体通知适配说明

1.媒体通知是什么

媒体通知(或称 Media template / Media style)是 Android 标准通知样式的一种,自 API 21(Android 5.0) 引入,方便用户直接控制媒体内容,常见于音乐类、广播类应用。

MIUI 10 完全兼容该通知样式,并调整了视觉风格,以符合系统风格,如下图(第一条通知)。

2. 为什么要用系统的媒体通知?

音乐类应用已经都有自己的「自定义通知」可以控制音乐,那为什么还要用系统的媒体通知?

调用系统的媒体通知,系统就能做针对性的优化,如:

  • 正在播放的媒体通知默认置顶 + 默认展开为大视图。
  • 正在播放的媒体通知默认会出现在锁屏上(置顶+大视图)。

这些都能让内容更充分地曝光,也有利于提升用户体验。

注:不同于原生 Android O 允许所有通知出现在锁屏上,MIUI 限制了出现在锁屏的通知类型,以减少用户打扰。如果需要出现在锁屏上,需要前往设置 – 通知和状态栏 – 通知管理,找到对应应用,开启‘’锁屏通知‘’。

3. 如何适配系统媒体通知

3.1 媒体通知的两种视图

媒体通知有两种视图,分别称为:

  • 标准视图 / compact view:标准的通知高度,最多显示3个按钮(actions)。
  • 大视图 / expanded view:面积更大,最多显示5个按钮。

3.2 适配媒体通知

MIUI 10的媒体通知,基于 Android O,以下是几个重要的接口:

媒体通知代码示例如下:

Notification = new Notification.Builder()
    .setContentTitle("Havana(feat.Young Thug")
    .setContentText("Camila Cabello - Havana")
    .setSmallIcon(mySmallIcon)
    .setLargeIcon(album)
    .addAction(previousAction)
    .addAction(playAction)
    .addAction(nextAction)
    .addAction(playlistAction)
    .addAction(favoriteAction)
    .setOngoing(true)
    .setStyle(newNotification.MediaStyle()
        .setShowActionsInCompactView(1,2,3)
        .setMediaSession(mySession)))
    .build();

详细接口说明见官方文档:https://developer.android.com/reference/android/app/Notification.MediaStyle

不过,以下接口在 MIUI 10 无法生效:

以上接口都可能会产生不协调的颜色,故暂时屏蔽。

4. FAQ

4.1. 如何判断 MIUI 版本

有以下方法:

android.os.SystemProperties.get("ro.miui.ui.version.code", "7");// 如果返回值是「8」,就是 MIUI 10

android.os.SystemProperties.get("ro.miui.ui.version.name", "");// 如果返回值是「V10」,就是 MIUI 10

4.2. 只有 MIUI 10 支持媒体通知吗

其实 MIUI 9 也支持媒体通知,但因为没有做好优化。所以,可以大体认为「只有 MIUI 10 支持媒体通知」,含国内版和国际版,且样式和逻辑统一。

4.3. 只要是 MIUI 10 就支持媒体通知吗?

是的。因为 Android 原生从 API 21 (android 5.0)就支持媒体通知了,详见 https://developer.android.com/reference/android/app/Notification.MediaStyle。而 MIUI 10 最低是兼容到 Android 6.0,所以只要是 MIUI 10就支持媒体通知。

4.4. MIUI 10 会禁用自定义通知吗

不会。但系统无法识别自定义通知的具体内容,只会当成普通通知处理。

4.5. MIUI 10 媒体通知的样式以后会变化吗

有可能。主要取决于:

  • Android 增加新的接口:我们后续会尽力兼容新的接口,并以此调整样式。
  • 业务需求和用户反馈。

4.6. MIUI 以前自己做的锁屏音乐界面还有用吗

在 MIUI 10 上没有用了。由于那个页面的实现方式有较多问题,因此我们在 MIUI 10 上弃用了,改由在锁屏上显示媒体通知,来实现锁屏音乐控制的需求。

4.7. 第三方应用自己做的锁屏页面(如音乐类或运动类的覆盖式)还能用吗?

可以继续使用,MIUI 10 没有限制这个能力(不过前提是开启了「锁屏显示」的权限)。但我们不建议开发者做这么一个覆盖式的页面,因为用户体验很差,还是希望能够用媒体通知替代。

4.8. 如何测试

升级到  MIUI 10 最新开发版即可,支持的机型和下载链接如下(找到对应机型的最新开发版):

什么是包名 (Package Name)?

小米应用商店按照符合Android标准的原则进行设计,使用包名(Package Name)作为应用的唯一标识。即:包名必须唯一,一个包名代表一个应用,不允许两个应用使用同样的包名。包名主要用于系统识别应用,几乎不会被最终用户看到。

包名的命名规则

只能包含大写字母(A到Z)、小写字母(a到z)、数字和下划线,以用点(英文句号)分隔称为断,至少包含2个断,隔开的每一段都必须以字母开头。

避免包名冲突

因为包名是唯一标识,为了避免与其他应用的包名重复,产生冲突,您可以这样命名:

将您的域名反转过来作为前缀,比如如果您的域名是zan.com,那么包名可以用com.zan开头,这样可以有效的避免重复

在后面增加描述产品名称的字符,比如您的应用是视频应用,可以命名为com.zan.video

如果您没有域名,可以使用自己的邮箱作为前缀,比如 com.xiaomi.WoDeYouXiang

包名冲突如何处理?

如果您发现您尚未发布的应用,包名和其他开发者已经发布的应用重复了,建议立刻修改应用的包名,避免冲突。

如果您的应用已经发布了,但是在小米开发者站上传应用时,被告知已经有其他开发者上传了同包名的应用,可以按照指示,进入问题工单系统,联系我们进行处理。

请注意

应用发布后,请不要修改包名,一旦您修改了包名,就会被当作一个新的应用,旧版用户也无法收到应用商店的升级提醒。

VIVO消息推送 Android PUSH-SDK API接口文档

VIVO消息推送 Android PUSH-SDK API接口文档

点击此处下载 PUSH SDK接入文档

版本号:3.0.0.4

一、 接口概述

本SDK中有两个开放类,分别为:Push操作类PushClient、回调接收类OpenClientPushMessageReceiver/ IPushActionListener。

PushClient 为功能接口,用于调用Push相关功能; 

IPushActionListener 为操作回调接口,用于功能接口状态回调;

OpenClientPushMessageReceiver 为回调接口,用于Push的数据结果返回;

1. PushClient功能类

PushClient提供Push服务的对外API列表,采用单例模型,通过getInstance(Context context)获得该对象。

initialize      初始化Push服务;

checkManifest   检查AndroidManifest是否正确声明组件和权限;

turnOnPush      打开PUSH;

turnOffPush     关闭PUSH;

getRegId        获取当前设备的当前应用的唯一标识;

bindAlias       设置应用别名;

unBindAlias     取消应用别名;

getAlias        获取应用别名;

setTopic        设置主题;

delTopic        删除主题;

getTopics       获取主题;

isSupport       当前系统是否支持PUSH;

2. IPushActionListener操作回调类

IPushActionListener类提供PushClient的操作回调。

onStateChanged  操作状态返回,详见操作码;

3.OpenClientPushMessageReceiver操作回调类

OpenClientPushMessageReceiver类提供基础消息的接收和操作结果的反馈,需要开发者继承本类,并重载相关的方法;同时,还需要在AndroidManifest.xml静态注册。

onReceiveRegId  RegId结果返回,只有首次获取到或regId发生变化时才会回调;

onNotificationMessageClicked  通知被点击时回调(仅用于兼容老版本)。

4. 公共状态码

状态码用于返回各项操作的结果,常用于回调接收类中状态返回,以下为公共状态码:

0       操作成功;

1       操作成功,此动作在未操作前已经设置成功;

101     系统不支持;

102     PUSH初始化异常,请重现初始化PUSH;

1001    一天内调用次数超标;

1002    操作频率过快;

1003    操作超时;

1004    应用处于黑名单;

1005    当前push服务不可用;

10000   未知异常;

10001   topic错误,例如传入appid/;

10002   topic错误, 例如appid/null;

10003   app包名与配置不匹配,例如传入com.yyy;

10004   appkey不匹配,例如传入appkey:bcd不存在;

10005   appid传入错误,例如未申请此appid,传入111;

10006   别名长度超过40;

10007   别名订阅时appkey不存在;

10008   开放平台暂不支持tag订阅;

二、 API接口

PushClient类

① Initialize

功能介绍:初始化push服务,可以提高后台发送消息的实时性。

接口定义:void initialize();

补充:建议每次手机启动后,都调用一次,确保Push服务能够正常运行。

② turnOnPush

功能介绍:打开应用push开关,绑定应用,成功后便可接收到当前应用的推送消息。

接口定义:void turnOnPush(IPushActionListener listener);

参数说明:listener: 状态监听;

补充:打开push成功后无需重复调用。

③ turnOffPush

功能介绍:关闭应用push开关,解除绑定应用,解绑后将收不到当前应用的推送消息。

接口定义:void turnOffPush(IPushActionListener listener);

参数说明:listener: 状态监听;

补充:关闭push成功后无需重复调用。

④ getRegId

功能介绍: 获取当前设备的当前应用的唯一标识,后台可基于此标识发送通知。

接口定义:String getRegId();

返回值:当前设备的当前应用的唯一标识;

补充:此方法仅在打开PUSH成功后可以获取,否则为null。

⑤ bindAlias

功能介绍:在注册成功,收到regId之后,即可设置别名,绑定当前设备的当前应用的别名,可以理解为regId的别名,开发者可以将别名设置为自己应用帐号系统的帐号,或者设备标识等。然后通过此别名发送消息。

接口定义:bindAlias(String alias, IPushActionListener listener);

参数说明:alias:别名; listener: 状态监听。

**状态码 描述**

30001   设置别名失败:请打开push开关;

30002   设置别名失败:订阅别名为空;

30003   设置别名失败:别名设置超长,字符长度超过70;

补充:绑定别名,同一个别名仅能绑定一个regId。当regId已绑定了别名A,若调用此接口绑定别名B,则与别名A的绑定关系会自动解除。此接口与 unBindAlias 一天内最多调用100次,两次调用的间隔需大于2s。

⑥ unBindAlias

功能介绍:删除别名,解除绑定当前应用别名,解绑成功后后台将无法通过别名的方式向应用发消息。

接口定义:

void unBindAlias(String alias);
void unBindAlias(String alias, IPushActionListener listener);

参数说明: alias:别名; listener:状态监听。

**状态码 描述**

30001   删除别名失败:请打开push开关;

30002   删除别名失败:订阅别名为空;

30003   删除别名失败:别名设置超长,字符长度超过70;

补充:此接口与 bindAlias 一天内最多调用100次,两次调用的间隔需大于2s。

⑦ getAlias

功能介绍:获取当前设备的应用别名,后台可基于此别名发送通知。

接口定义:String getAlias();

返回值:当前设备的应用别名。

⑧ checkManifest

功能介绍:校验接入是否异常。通过调用该API来检查AndroidManifest.xml是否正确声明了本SDK要求的所有组件和权限。当有组件和权限未定义,或者组件的属性声明错误时抛出异常VivoPushException。

接口定义:void checkManifest()。

⑨ setTopic

功能介绍:在注册成功,收到regId之后,即可设置主题;开发者可根据用户订阅的主题实现分组。

接口定义:setTopic(String topic, IPushActionListener listener);

参数说明:topic : 需要订阅的主题名; listener : 状态监听。

**状态码 描述**

20001   设置主题失败:请打开push开关;

20002   设置主题失败:订阅主题为空;

20003   设置主题失败:别名设置超长,字符长度超过70;

20004   设置主题失败:订阅次数太频繁或已订阅数过多;

补充:同一个regId可设置多个主题,最多可订阅500个主题。当regId已设置了topicA,若调用此接口设置topicB,则regId同时订阅了topicA和topicB。此接口与 delTopic 一天内最多调用500次,两次调用的间隔需大于2s。

⑩ delTopic

功能介绍:删除已经设置的主题。

接口定义:delTopic(String topic, IPushActionListener listener);

参数说明:topic 需要取消订阅的主题名; listener 状态监听。

**状态码 描述**

20001   设置主题失败:请打开push开关;

20002   设置主题失败:订阅主题为空;

20003   设置主题失败:别名设置超长,字符长度超过70;

20004   设置主题失败:订阅次数太频繁或已订阅数过多;

补充:此接口与 setTopic 一天内最多调用500次,两次调用的间隔需大于2s。

⑪ getTopics

功能介绍:获取当前设备的应用主题,后台可基于此主题发送通知。

接口定义:List getTopics();

返回值:当前设备已经设置的应用主题;

⑫ isSupport

功能介绍:用于判断当前系统是否支持PUSH服务。

接口定义:boolean isSupport();

返回值:true 系统支持; false 系统不支持。

⑬ onReceiveRegId

功能介绍:RegId结果返回。当开发者首次调用turnOnPush成功或regId发生改变时会回调该方法。

接口定义:void onReceiveRegId(Context context, String regId);

参数说明:context : 应用上下文; regId: 当前设备的当前应用的唯一标识;

⑭ onNotificationMessageClicked(仅用于兼容老版本)

功能介绍:通知被点击后的结果返回。当push发出的通知被点击后便会触发onNotificationClicked通知应用。

接口定义:void onNotificationMessageClicked(Context context, UPSNotificationMessage msg);

参数说明:context : 应用上下文; msg: UPSNotificationMessage通知消息结构体;

**UPSNotificationMessage 包含以下字段**
msgId:通知id。
title:通知标题。
content:通知内容。
skipContent:通知自定义内容。
params:自定义键值对。

三、统一推送联盟API介绍

① turnOnPush

功能介绍:做了相应的初始化操作,建议用户在自己应用的Application中的onCreate()方法中调用turnOnPush操作。

接口定义:

void turnOnPush(Context context, UPSTurnCallback callback)

参数说明:

context : 应用上下文;

Callback:UPSTurnCallback 回调结构,包含以下方法;

 .getReturnCode()  获取返回状态,0代表成功,其他值代表失败。

② registerToken

功能介绍:注册push,获取申请的regId

接口定义:

void registerToken(final Context context, String appID, String appKey, String appSecret, final UPSRegisterCallback callback)

参数说明:

context : 应用上下文;

appID: 应用在Vivo开放平台申请的APPId;

appKey: 应用在Vivo开放平台申请的APPKey;

appSecret: 应用在Vivo开放平台申请的APPSecret;

callback: UPSRegisterCallback回调结构,包含以下方法;

 .getReturnCode() 获取返回状态,0代表成功,其他值代表失败;

 .getToken()  获取应用申请的regId。

③ unRegisterToken

功能介绍:接注册push,关闭push功能

接口定义:

void unRegisterToken(Context context, final UPSRegisterCallback callback)

参数说明:

context : 应用上下文;

Callback:UPSRegisterCallback回调结构,包含以下方法;

.getReturnCode():获取返回状态,0代表成功,其他值代表失败。

④ turnOffPush

功能介绍:该功能暂时未具体实现,要关闭push功能,请调用上面的unRegisterToken接口

接口定义:

void turnOffPush(Context context, final UPSTurnCallback callback)

参数说明:

context : 应用上下文;

Callback:UPSTurnCallback回调结构,包含以下方法;

.getReturnCode():获取返回状态,0代表成功,其他值代表失败。

Logcat使用限制

Logcat是Android 系统提供的实时查询系统日志的命令工具,帮助开发者在开发调试阶段定位问题,优化自身功能。然而对logcat日志使用不当也会导致一些问题,如个人信息泄漏/功耗等,而开发者对这些问题则关注的少,为此vivo针对logcat做了部分的定制,以防止出现类似的问题。

1. 打印行数限制

vivo限制了logcat输出日志的频率,限制单个进程每秒只能打印 250行,一秒内超出的日志将会直接丢弃(每一秒的日志都是重新计数),并且打印以下的日志:

该日志是对应的进程中打印的,drop 关键字后面表示了当前丢失了多少行的日志,行数限制不区分日志等级。

应用开发者需要控制自身的日志打印量,不能无休止的刷日志。

2. 敏感数据过滤

任何的Android手机只要打开了开发者选项,都可以通过logcat打印系统日志,若日志中有个人数据打印则非常危险,为此vivo在logcat的输出增加了敏感信息脱敏功能,输出的日志中有敏感的数据(如:手机号,设备ID,经纬度,ip地址,URL等),都会全部转换为星号。

未脱敏日志

脱敏后日志

备注:在新的机型上,系统做了区分处理,debug版本应用打印的内容不会脱敏,release版本的会脱敏,满足开发者的调试需要。

3. Logcat调用限制

APP若在运行时需要读取系统日志定位自身发生的异常,调用 logcat 命令时必须增加 -d 参数,即调用logcat不能阻塞进程一直等待;若应用未增加此参数,则系统会特殊处理,实现同等效果(增加参数-d)。如下格式:logcat -d 

增加 -d 参数后,logcat 仅仅会读取当前系统缓存的日志,然后直接退出,不会一直阻塞住。未增加 -d 参数则会持续输出系统日志,对系统负载影响大,特别是系统日志量多的时候,对功耗的影响会非常的大。

Android Q应用适配指南

一、如何体验升级android Q

1.1 vivo机器升级android Q指导

vivo NEX S, vivo NEX A,vivo X27已经提供有可升级到Android Q的开发者预览版本,开发者可以直接通过以下链接指导进行升级试用:

https://dev.vivo.com.cn/documentCenter/doc/210

1.2 vivo远程真机调试

vivo云测平台已经提供关于vivo NEX S, vivo NEX A,vivo X27 Android Q的远程真机服务,开发者可以直接通过以下链接进入远程真机进行试用体验:

https://vcl.vivo.com.cn/#/home/index

1.3 google原生机升级android Q

开发者持有Pixel系列的机器可以直接ota升级,或者下载镜像升级,具体见链接:

https://developer.android.google.cn/preview/download

二、Android Q兼容性变化

2.1 非SDK接口限制

Android 平台开始限制您的应用在 Android 9(API 级别 28)中使用非 SDK 接口,灰名单和白名单的非 SDK 接口已有更新。

适配建议: 

依赖非SDK接口的应用应尽快迁移到 SDK 替代方案,如部分非SDK接口无替代方案,则请求新的公共API。

2.2 重大隐私权变更

2.2.1 分区存储

以 Android Q 为目标平台的应用(以及选择接受这些变更的应用),Android Q 更改了应用对设备外部存储设备中的文件(例如存储在路径 /sdcard 下的文件)的访问方式,只有满足相关条件,应用才能访问其他应用创建的文件。

适配建议: 

如果应用以 Android Q 为目标平台,则在访问外部存储设备中的文件时会进入过滤视图,具有过滤视图的应用对其创建的文件始终拥有读/写权限,无论文件位于特定于此应用的目录以内还是以外。只有在满足以下两个条件时,您的应用才能访问其他应用创建的文件:

(1)您的应用已获得 READ_EXTERNAL_STORAGE 权限。

(2)这些文件位于以下其中一个明确定义的媒体集合中:

照片:存储在 MediaStore.Images 中。

视频:存储在 MediaStore.Video 中。

音乐文件:存储在 MediaStore.Audio 中。

2.2.2 设置位置信息

Android Q 引入了新的位置权限,区分应用前台和后台获取位置信息。如果您的应用在后台时请求访问设备位置信息,则会影响您的应用。如果用户只授权前台获取位置信息权限, 应用在返回后台后则不能再获取位置信息。

适配建议: 

使用新权限在后台访问位置信息,并在没有后台位置信息更新的情况下确保优雅降级。应用应向用户说明他们需要允许该应用始终都能访问设备位置信息,以确保正常运行,然后请求在后台访问位置信息。

2.2.3 后台应用启动

Android Q 对应用可启动 Activity 的时间施加了限制,只有在满足相关条件时才能启动 Activity。此项行为变更适用于在 Android Q 上运行的所有应用。

适配建议: 

检查activity是否符合启动的条件,后台应用都应创建通知以便向用户提供信息。

2.2.4 硬件标识符获取

从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可重置标识符(包含 IMEI 和序列号),会对应用依赖device id的功能产生影响。影响在 Android Q 上运行的所有应用,即使这些应用以 Android 9(API 级别 28)或更低版本为目标平台。

适配建议: 

请关注厂商近期发布的适配指导。

2.3 加固版本兼容

Android每个大版本升级,加固方案商都会对android大版本适配和兼容。依赖加固固件的应用需要及时更新最新的加固固件来适配Android新版本,避免加固导致应用无法正常使用或影响应用稳定性。

2.4 第三方SDK兼容

应用会依赖第三方的SDK Jar或Native so库等第三方SDK,Android大版本升级第三方SDK会存在不兼容的问题,需要推动以及更新依赖的第三方SDK适配android Q。

三、参考链接

(1)Android Q所有应用行为变更:https://developer.android.google.cn/preview/behavior-changes-all

(2)Android Q targetSDK 29应用行为变更:https://developer.android.google.cn/about/versions/10/behavior-changes-10

(3)Android Q 中的隐私权:https://developer.android.google.cn/preview/privacy

(4)google pixel系列镜像升级包:https://developer.android.google.cn/preview/download

OPPO推送消息能力Android SDK集成

OPPO推送消息能力Android SDK集成

版本说明

目前SDK版本为V3.1.0,仅支持ColorOS 3.1或以上版本的手机系统,如无特殊说明,兼容历史版本。

SDK接入流程

开通推送权限

具体权限申请流程可参考【推送服务开启指南

获取秘钥等验证信息

申请通过后,可在OPPO推送平台-配置管理-应用配置-页面查看AppKey、AppSecret和MasterSecret(仅开发者帐号(主帐号)可查看)。

名词解释:AppKey、AppSecret客户端的身份标识,客户端SDK初始化时使用。

SDK集成步骤

注册并下载SDK

Android的SDK以aar形式提供,第三方APP只需要添加少量代码即可接入OPPO推送服务。
代码参考demo下载:heytapPushDemo
下载aar文件,即3.1.0版本sdk:com.heytap.msp_3.1.0.aar

aar依赖

第一步:添加maven仓库

repositories {
    google()
    mavenCentral()
}

第二步:添加maven依赖

implementation(name: 'com.heytap.msp_3.1.0', ext: 'aar')
//以下依赖都需要添加
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'commons-codec:commons-codec:1.6'
implementation 'com.android.support:support-annotations:28.0.0'(SDK中的接入最小依赖项,也可以参考demo中的依赖)

第三步:添加aar配置
在build文件中添加以下代码

Android{
....

repositories {
    flatDir {
        dirs 'libs'
    }
}

....
}

配置AndroidManifest.xml

1)OPPO推送服务SDK支持的最低安卓版本为Android 4.4系统。
<uses-sdk  android:minSdkVersion="19"/>
 
2)推送服务组件注册
//必须配置
<service
   android:name="com.heytap.msp.push.service.XXXService"    
  android:permission="com.heytap.mcs.permission.SEND_PUSH_MESSAGE"
 android:exported="true">
    <intent-filter>
     <action android:name="com.heytap.mcs.action.RECEIVE_MCS_MESSAGE"/> 
<action android:name="com.heytap.msp.push.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service>(兼容Q版本,继承DataMessageCallbackService)
 
<service
   android:name="com.heytap.msp.push.service.XXXService"     
android:permission="com.coloros.mcs.permission.SEND_MCS_MESSAGE"
android:exported="true">
    <intent-filter>
     <action android:name="com.coloros.mcs.action.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service>(兼容Q以下版本,继承CompatibleDataMessageCallbackService)

注册推送服务

1)应用推荐在Application类主进程中调用HeytapPushManager.init(…)接口,这个方法不是耗时操作,执行之后才能使用推送服务
2)业务需要调用api接口,例如应用内开关开启/关闭,需要调用注册接口之后,才会生效
3)由于不是所有平台都支持MSP PUSH,提供接口HeytapPushManager.isSupportPush()方便应用判断是否支持,支持才能执行后续操作
4)通过调用HeytapPushManager.register(…)进行应用注册,注册成功后,您可以在ICallBackResultService的onRegister回调方法中得到regId,您可以将regId上传到自己的服务器,方便向其发消息。初始化相关参数具体要求参考详细API说明中的初始化部分。
5)为了提高push的注册率,你可以在Application的onCreate中初始化push。你也可以根据需要,在其他地方初始化push。如果第一次注册失败,第二次可以直接调用PushManager.getInstance().getRegister()进行重试,此方法默认会使用第一次传入的参数掉调用注册。

混淆配置

-keep public class * extends android.app.Service
-keep class com.heytap.msp.** { *;}

详细API说明

HeytapPushManager

接口定义

      /**
     *初始化MSP服务,创建默认通道
     *@param context必须传入当前app的context
     *@param needLog是否需要设置log
     */
        1)void init (Context context,bool needLog)
    /**
     *获取Mcs的包名
     */
        2)string getMcsPackageName ()

    /**
     *获取接收消息服务的action
     */
        3)string getReceiveSdkAction ()

    /**
     *判断是否手机平台是否支持PUSH
     @param context传入应用上下文
     *@return true 表示手机平台支持PUSH, false表示不支持
     */
        4)boolean isSupportPush (Context context)
    /**
     * (旧埋点)消息事件统计接口,用于进行额外的Push消息事件统计   *
     * @param context 应用的context
     * @param message 需要上报的消息或消息列表
     */
    //会在以后的版本逐渐废弃
        5)void statisticMessage (Context context, MessageStat message)
        6)void statisticMessage (Context context, List < MessageStat > messages)

    /**
     * (新埋点)消息事件统计接口,用于进行额外的Push消息事件统计,如有需要使用,请开发者提前与OppoPush团队进行充分沟通和确认,为了防止业务方频繁调用上报
     *
     * @param context 应用的context
     * @param eventId 需要上报的eventId事件,上报的eventId在EventConstant类中
     *
        7)void statisticEvent(Context context,String eventId , DataMessage message)

    /**
     *获取registerId
     */
        8)String getRegisterID ()

    /**
     *设置registerId
     */
        9)void setRegisterID (String mRegisterID)

    /**
     * 注册MSP推送服务
     * @param applicatoinContext必须传入当前app的applicationcontet
     * @param appKey 在开发者网站上注册时生成的,与AppKey相对应
     * @param appSecret 与AppSecret相对应
     * @param ICallBackResultService SDK操作的回调
     */
        10)void register (Context applicatoinContext, String appKey, String appSecret, ICallBackResultService
            ICallBackResultService );

    /**
     * 设置appKey等参数,可以覆盖register中的appkey设置
     * @param appKey 在开发者网站上注册时生成的key
     * @param appSecret
     */
        11)void setAppKeySecret (String appKey, String appSecret);

    /**
     *获取pushcall回调
     */
        12)ICallBackResultService getPushCallback ()

    /**
     * 设置sdk操作回调处理,可以覆盖register中的ICallBackResultService设置
     * @param ICallBackResultService sdk操作回调处理
     */
        13)void setPushCallback (ICallBackResultService ICallBackResultService );


    /**
     * 解注册MSP推送服务
     */
        14)void unRegister ();

    /**
     * 获取注册OPush推送服务的注册ID,此方法用于提高注册率,里面调用的是注册的逻辑,引用之前传入的参数
     */
        15)void getRegister ()

    /**
     * 暂停接收MSP服务推送的消息
     */
        16)void pausePush ();

    /**
     * 恢复接收MSP服务推送的消息,这时服务器会把暂停时期的推送消息重新推送过来
     */
        17)void resumePush ();

    /**
     * 清除通知
     */
        18)void clearNotifications ()

    /**
     * 获取MSP推送服务状态
     */
       19)void getPushStatus ();

    /**
     * 获取MSP推送服务SDK版本(例如”2.1.0”)
     *
     * @return SDKVersion
     */
       20)String getSDKVersionCode ();

    /**
     * 获取MSP推送服务SDK名称
     *
     * @return SDKVersionName
     */
        21)String getSDKVersionName ();

    /**
     * 获取MSP推送服务MCS版本(例如“2400”)
     *
     * @return PushVersionCode
     */
        22)String getPushVersionCode ();

    /**
     * 获取MSP推送服务MCS版本(例如“2.4.0”)
     *
     * @return PushVersionName
     */
        23)String getPushVersionName ();

    /**
     * 设置允许推送时间 API
     *
     * @param weekDays 周日为0,周一为1,以此类推
     * @param startHour 开始时间,24小时制
     * @param endHour 结束时间,24小时制
     */
        24)void setPushTime (List< Integer > weekDays, int startHour, int start Min, int endHour, int endMin);

    /**
     * 弹出通知栏权限弹窗(仅一次),OS12.1及之后的ColorOS版本废弃该接口,不生效
     */
        25)void requestNotificationPermission ();

    /**
     * 打开通知栏设置界面
     */
        26)void openNotificationSetting ();

    /**
     * 获取通知栏状态,从callbackresultservice回调结果
     */
        27)void getNotificationStatus ();

    /**
     * 打开应用内通知
     *@see ISetAppNotificationCallBackService
     */
        28)void enableAppNotificationSwitch (ISetAppNotificationCallBackService callBackService);

    /**
     * 关闭应用内通知
     *@see ISetAppNotificationCallBackService
     */
        29)void disableAppNotificationSwitch (ISetAppNotificationCallBackService callBackService);

    /**
     * 获取应用内通知开关
     *@see IGetAppNotificationCallBackService
     */
        30)void getAppNotificationSwitch (IGetAppNotificationCallBackService callBackService);

接口说明

应用在没有获取到registerId时,需要先调用register进行注册,注册成功后才可以进行后续操作。如果调用register注册失败,可以调用getRegister使用上一次传入的参数进行重试。
调用requestNotificationPermission显示通知权限弹窗,用户可通过弹窗自行选择是/否打开应用的通知权限。建议在Activity的onResume方法中调用该接口以避免和其他弹窗重叠。重复调用该接口,弹窗也仅会显示一次。

ICallBackResultService

接口定义

//注册的结果,如果注册成功,registerID就是客户端的唯一身份标识
void onRegister(int responseCode, String registerID);

//反注册的结果
void onUnRegister(int responseCode);
 
//获取当前的push状态返回,根据返回码判断当前的push状态,返回码具体含义可以参考[错误码]
void onGetPushStatus(int responseCode,int status);
public class PushStatus {
    public static final int PUSH_STATUS_START = 0;
    public static final int PUSH_STATUS_PAUSE = 1;
    public static final int PUSH_STATUS_STOP = 2;
}
 
//获取当前通知栏状态,返回码具体含义可以参考[错误码]
void onGetNotificationStatus(int responseCode,int status);
public class NotificatoinStatus {
    public static final int STATUS_OPEN = 0;
    public static final int STATUS_CLOSE = 1;
}
 
//获取设置推送时间的执行结果
void onSetPushTime(int responseCode, String pushTime)
 
//错误码返回的接口(当前主要是用于调用频繁的回调,后续可做拓展)
void onError(int code, String msg)

接口说明

所有回调都需要根据responseCode来判断操作是否成功,0 代表成功,其他代码失败,失败具体原因可以查阅附录中的错误码列表。
onRegister接口返回的registerID是当前客户端的唯一标识,app开发者可以上传保存到应用服务器中,在发送push消息是可以指定registerID发送。

ISetAppNotificationCallBackService

接口定义

//设置应用内通知开关结果,如果成功返回0,失败返回非0,具体指参考错误码
void onSetAppNotificationSwitch(int responseCode);

接口说明

建议复用使用一个callBackService,避免后面对象覆盖调前面一个对象导致前面的callBackService无返回。

IGetAppNotificationCallBackService

接口定义

//获取应用内通知开关结果,如果成功返回0,失败返回非0,具体指参考错误码
//appSwich:0:未定义状态(不校验开关),1:打开状态,2:关闭状态
void onGetAppNotificationSwitch(int responseCode, int appSwitch);

接口说明

建议复用使用一个callBackService,避免后面对象覆盖调前面一个对象导致前面的callBackService无返回。

性能指标和SDK包大小

1)性能指标:响应时间小于500毫秒
2)sdk包大小:500kb以内

OPPO应用商店应用名称和包名命名规范

OPPO应用商店应用名称和包名命名规范

应用名称定义

应用名称是一款应用产品的表达信息,显示在客户端界面供手机用户搜索和下载的重要标识。

应用名称规范

1、应用名称不得超过15个汉字字符或30个英文字符,不得含有@#¥%……&*等特殊符号;名称和应用功能之间必须有所关联。

2、应用名称不得含有政治敏感、色情、暴力血腥、恐怖内容及国家法律法规禁止的其他违法内容;未经授权不得使用第三方享有合法权益的商标、品牌标识等内容或与之相似的内容。

3、应用名称不得混有商业化用语、其他热门应用名称、流行用语、关键词堆砌、“国家级”、“最高级”等新广告法明令禁止等其他与应用功能无关的词语。

4、应用名称不得以计算器、日历、贷款,网赚等广义归纳类、普遍且不具有识别性的词汇来命名;在此类名称增加副标题也不符合上架条件。

5、无正当理由,应用名称不得与已上架其他应用名称重复或混淆,不得以添加无实质意义的功能词/分类词后缀、字母、符号等任何方式作为避开、绕开平台规则及规范;如XXXX最新版,XXXX2,XX贷款手机借款均不符合上架规定。

应用名称如果被占用

1)开发者有商标权证明,可以先在副标题填写公司名称或者简称,同时在后台补充有效的商标权证明。若持有商标建议按照侵权投诉流程进行侵权投诉。

2)如果没有商标权证明,且商店存在同名同分类应用,建议更换其他名称;(安卓手机可下载OPPO软件商店查看)

3)应用名称如果被占用,且商店不存在同名同分类应用在架,可添加副标题,建议填写公司名称,品牌,不可使用其他无关字段或其他蹭热度字段,平台经核实后将对副标题进行删除。

7、如果开发者针对不同群体分别开发客户端,可使用副标题或者-。建议尽可能简洁清晰,如:贝立方幼儿园(家长端)或者 贝立方幼儿园-家长端。

8、不允许在名称中使用OPPO或者ColorOS等元素,应用名称建议与软著尽可能一致,如果软著上的名称不符合上述规定,建议咨询客服

包名定义

1)OPPO开放平台按照符合Android标准的原则设计,使用包名(Package Name) 作为应用的唯一标识。一个包名代表一个应用,不允许两个应用使用同样的包名。如果您发现您尚未发布的应用,包名和其他开发者已经发布的应用重复了,您可以通过申诉的形式认领该应用,或者改包名重新发布。

2)安卓的包名是针对安卓系统的app的识别标识,这个标识是不被用户直接看到的,每个app都有自己的标识,可以由大写小写字母,数字,点或-所组成,一台手机不能安装两个相同包名的应用,如果一个应用在后续版本中改了包名,那在那些应用商店里就会检查不到这个软件的新版本,而在这个应用里更新的版本则会出现第二个相同的应用在系统或桌面上,这个包名是由开发者自己取的。如手机qq包名为:com.tencent.mobileqq,如运营商务人员不清楚,可以咨询贵司技术人员。

包名规范

1)OPPO游戏中心的游戏包名需要统一以 .nearme.gamecenter结尾, 否则无法通过审核。若您的应用非游戏中心的游戏,请勿以 .nearme.gamecenter结尾。

2)应用发布后,请勿修改包名,一旦您修改了包名就会被当做一个新的应用发布,旧版用户也无法收到应用商店的升级提醒。

3)包名中请勿带有OPPO元素,不得暗示误导或其关联公司是该APP的来源或开发者。

OPPO Sign获取指引

什么是 OPPO Sign

OPPO Sign是应用的签名摘要信息通过OPPO的加密算法生成的MD5字符串,主要用于接入OPPO帐号、游戏SDK时候做应用身份校验。

什么场景需要 OPPO Sign

同时符合如下两个条件的应用需要填写OPPO Sign
1、需要接入帐号SDK或者游戏SDK。
2、未发布的应用(上传应用APK后我们会自动根据前面信息计算出对应的OPPO Sign信息,因此只需要未发布的应用填写OPPO Sign)。

如何获取OPPO Sign

您可以选择在PC端(Windows)或者手机端(Android)去获取安装包的签名摘要信息。

Windows 获取指引

1)下载OPPOSign.zip

2)解压文件,然后在电脑上运行OPPO Sign程序;

3)按照操作指引拖入APK文件;

4)获取到OPPO Sign,复制文本。

手机端获取指引

1)在手机上安装所需要获取OPPO Sign的应用;
2)在手机上安装获取签名工具
3)打开获取签名工具,输入所需获取OPPO Sign应用的包名,点击“获取签名信息”。

removeListener 移除监听器 app开发接入高德猎鹰轨迹服务

用做网页的技术做APP
一门提供标准化的jsbridge-mini.js库,您只需要在页面引用执行JS即可实现各种原生APP、原生PC的功能能力。

==================APP端==================
【APP端】(安卓版&苹果版)目前提供200+原生功能,2000+JS映射接口,用做网站的技术即可实现各种原生APP能力、APP demo地址https://www.yimenapp.com/doc/demo.cshtml下载教程:
♦ JS-SDK 引用方式:
♦ 普通网页 script 方式加载:下载最新版,请在页面上调用 jsBridge 接口之前引用 jsbridge-mini.js 库;
♦ js module 方式引用:npm install ym-jsbridge 具体请参考 npm package
一门APP开发平台通用JS

removeListener 移除监听器 app开发接入高德猎鹰轨迹服务

1. 详情请查看 官方说明

2. 接入步骤:

2.1 去 高德开放平台 创建 Android / iOS 应用,将 Key 配置到打包平台生成 APP;

2.2 去 高德开放平台 创建 Web服务,将获得的 Key 用于调用 服务器端接口

2.3 调用服务器端接口创建 服务 和 终端 取得服务ID serviceId、终端ID terminalId;

2.4 用上一步取得的 serviceId、terminalId 调用APP端 jsBridge.amapTrack.startTrack 接口开启轨迹采集服务;

2.5 APP会把采集到的轨迹数据上传到高德平台,请调用 轨迹查询 接口获取轨迹数据(可用于可视化呈现,如展示在地图等);

核心代码示例,详情参阅demo

//移除监听器,不会再收到回调通知
//在需要时可重新调用 setListener
jsBridge.amapTrack.removeListener();

A标签执行JS示例代码

<a href="javascript:void(0)" onclick="zhixing()">执行</a> 
<!-- 写入一个A标签href值为"javascript:void(0)",定义点击事件onclick;-->
<script src="您的服务器URL/jsbridge-mini.js"></script>
<!-- 在您的服务器引入一门JS地址,请下载jsbridge-mini.js上传您自己的服务器获取链接;-->
<script type="text/javascript">
function zhixing() {


<!--这里可以直接复制JS核心代码到此{}括号内-->
//移除监听器,不会再收到回调通知
//在需要时可重新调用 setListener
jsBridge.amapTrack.removeListener();

}
</script>
<!--执行核心代码;
//如果需要进入页面就执行,去掉点击事件即可;-->

按钮执行JS示例代码

<button onclick="zhixing()" >执行</button>
<!-- //写一个按钮,定义点击执行事件; -->
<script src="您的服务器URL/jsbridge-mini.js"></script>
<!-- //在您的服务器引入一门JS地址,请下载jsbridge-mini.js上传您自己的服务器获取链接; -->
<script type="text/javascript">
function zhixing() {


<!--这里可以直接复制JS核心代码到此{}括号内-->
//移除监听器,不会再收到回调通知
//在需要时可重新调用 setListener
jsBridge.amapTrack.removeListener();

}
</script>
<!-- //执行核心代码;
//如果需要进入页面就执行,去掉点击事件即可; -->

高德提供通过WIFI和基站信息进行定位的服务吗?

高德提供通过WIFI和基站信息进行定位的服务吗?

高德提供的智能硬件定位服务,支持通过服务端上传WIFI和基站信息进行定位并获取经纬度。

该服务仅适用于没有Android或iOS系统的智能硬件产品使用,如您的产品支持Android或iOS系统,建议使用Android定位SDKiOS定位SDK以获得更精准效果和更丰富功能。

如您的产品适用于智能硬件定位服务,请先申请成为企业开发者,然后申请智能硬件定位Key,并在控制台-个人中心-帐号权限页面获取使用文档。

高德地图API服务的免费调用次数有什么限制?APP接入高德地图

高德地图API服务的免费调用次数有什么限制?APP接入高德地图

高德开放平台提供了基础服务和非基础服务,基础服务如地图、定位、搜索;非基础服务如海外地图服务、ETD、猎鹰等。以下免费配额说明适用于基础服务,非基础服务以您收到的申请结果为准。

“Web服务API”产品有调用次数限制,Android、iOS、JavaScript这些平台已封装的基础服务不限制日配额;

Web服务基础服务针对“不同类型开发者”的调用次数限制详情可参考“流量限制说明”

如何确定Key应该绑定哪种服务? APP开发接入高德导航

如何确定Key应该绑定哪种服务? APP开发接入高德导航

根据业务需求选择Key的服务平台(包括:Android、iOS、Web端、Web服务、智能硬件、微信小程序等),可点击相应平台可使用服务查看详情介绍。

其中Web服务指调用Web服务API接口使用的Key,Web端指PC或者H5网页调用使用的key

注意:Key的服务平台选择之后无法修改,如需要使用其他服务,可以再添加其他服务平台的Key。如下图所示:

高德开放平台 新旧版本的KEY有什么区别?

高德开放平台 新旧版本的KEY有什么区别?

新版Key:适用于所有新版本的API/SDK,拥有更加安全的密钥机制,更便捷的管理方式,更改数字签名和安全码更加灵活。

旧版Key:显示在密钥管理页面的下方,只适用于旧版本API/SDK。2015年2月1日起,我们将不再提供旧版Key的技术支持,并停止对其的维护。建议开发者申请新版Key,和升级新版SDK。

如您注册了新的Key,需下载最新的SDK/API才能使用。

新版Key对应新版SDK/API的关系如下:

JavaScript API:新版Key适用于高德地图JavaScript API V1.2服务插件及以上版本,不适用于JavaScript API V1.2旧版服务及下版本。

iOS 地图SDK:新版Key适用于高德地图 iOS SDK V2.3.0版本(含)以上版本;旧版Key只适用于V2.3.0(不含)以下版本。

Android 地图SDK:新版Key适用于高德地图 Android SDK V2.3.0版本(含)以上版本;旧版Key只适用于V2.3.0(不含)以下版本。

Android 定位SDK:Android定位SDK V1.3.0版本(含)以上版本;旧版Key只适用于V1.3.0(不含)以下版本。

Android 导航SDK:Android导航SDK V1.1.0版本(含)以上版本;旧版Key只适用于V1.1.0(不含)以下版本。

如新申请的Key对应了新下载的SDK包,还无法使用,请检查您的SHA1或Boundid是否绑定正确。

如果快速制作APP,可使用网站打包APP,一键在线做移动应用

如果快速制作APP,可使用网站打包APP,一键在线做移动应用

身处移动互联网的浪潮之中,可能每个人对于移动应用的制作都有一些自己的想法和愿景,却苦于没有技术支持或成本投入没有靠谱的核算技能,还有又受限于编程问题,往往无法着手实现。

互联网行业包括移动应用制作在国内市场潜力巨大,有正规的指导性意见和技术制作支持显得更为迫在眉睫。

一间名为一门APP的移动应用制作公司正是基于这些问题应运而生的。

一门APP旗下的移动应用制作官方是一app架设款能够帮忙助力制作者迅速实现APP的制作、测试、发布、管理和运营的全生命时间周期管理的智能移动应用服务官方。

官方运用标准Web技术制作iOS、Android原生应用,减少制作人工投入,提升制作效率,使得移动应用的制作成本、升级成本都低于传统制作模式。

让很多草根创业者的奇思妙想可以在合理范畴内实现互联网的体验价值。

 

同时,这款一门APP产品的一大优势还在于“云”和“端”两个大方向,通过“移动应用引擎”和“云引擎”两部分产品为移动制作者用户提供API,简化了APP的制作技术,极大提高APP制作和管理的效率。

制作官方上市以来,由于切合制作行业的瓶颈痛点,现在在国内主流的制作者服务商中,一门APP 已经与大部分第3方云服务达成深度合作,成为移webapp网站动领域知名的云服务聚合渠道。

 

     一门APP官方为不同需求的人提供了不同的产品,制作者是零基础开始开发App,这么官方会对应选择Deep Engine产品,用HTML五等标准Web语言去制作和开发App,省略很多制作程序,iOS和Android两个系统也是同时生成的。

非常方便,制作者能够完全抛开技术烦恼,专心投入于内容的策划。

     而另一个情况是针对现有移动应用制作者,加速制作和开发的时间周期

需求或希望能缩减迭代的难度和时间,这么选择SuperWebview产品。

在已有的App中嵌入SuperWebview,就能够使用Web语言去继续制作和开发了,这样缩减成本,缩短时间周期。

     按官方负责人说的,就是完全站在制作者的角度去提供服务,实现真正意义上的制作智能高效率。

 

专业做好移动应用制作者技术支持是一门APP 移动应用制作公司的服务使命,诸如Sublime Text、Eclipse和Webstorm这样耳熟能详的App制作工具都能够在一门APP上集成,同时支持使用您熟悉的HTML工具,再加上一门APP研发的制作插件,以二-三倍的效率app嵌套h5页面即可进行App开发。

编写移动应用界面问题能得到极速解决。

而针对移动应用功能单一性想要逐一制作而浪费成本效率的问题,一门APP是聚合了几乎所有国内主流的云服务模块,如支付、社交分享、视频直播、IM、语音会议等。

所想要的对应功能能够一键集成,迅速高效。