cocos2dx接入firebase后,点击消息通知栏闪退渲染异常

firebase正确接收到Token,需要安装谷歌三件套:

  • Google Play Store
  • Google Play services
  • Google Services Framework

推荐使用APP higoplay服务框架安装器一键安装。

小米MIUI12.5安装谷歌三件套后,打开Play商店会闪退,误解,MIUI系统的限制。

点击通知栏激活游戏闪退

less 复制代码
ActivityManager         system_process                       I  START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x14000000 pkg=com.yddm.haiwai.game cmp=com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity (has extras)} from uid 10055
zch                     com.yddm.haiwai.game                 D  MainActivity onDestroy
HostConnection          com.yddm.haiwai.game                 I  HostConnection::~HostConnection, pid=22091, tid=22157, this=0x7fff593f58c0, m_stream=0x7fff59dad240
<no-tag>                com.yddm.haiwai.game                 I  fastpipe: close connect
JniHelper               com.yddm.haiwai.game                 D  JniHelper::getJavaVM(), pthread_self() = 140734540272880
com.yddm.haiwai.game    com.yddm.haiwai.game                 I  type=1400 audit(0.0:3876): avc: denied { ioctl } for comm=474C54687265616420343535 path="/dev/fastpipe" dev="tmpfs" ino=5173 ioctlcmd=6869 scontext=u:r:untrusted_app:s0:c55,c256,c512,c768 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
WindowManager           com.yddm.haiwai.game                 E  
																android.view.WindowLeaked: Activity org.cocos2dx.lua.AppActivity has leaked window com.chsdk.moduel.floatball.view.FloatBallLayout{fe3196 V.E...... .......D 0,0-68,68} that was originally added here
																	at android.view.ViewRootImpl.<init>(ViewRootImpl.java:511)
																	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
																	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
																	at com.chsdk.moduel.floatball.control.FloatBall.addView(FloatBall.java:78)
																	at com.chsdk.moduel.floatball.control.FloatBall.show(FloatBall.java:40)
																	at com.chsdk.moduel.floatball.control.FloatBallHelper.show(FloatBallHelper.java:54)
																	at com.chsdk.internal.SdkLifeCycle.onLoginSuccess(SdkLifeCycle.java:260)
																	at com.chsdk.moduel.login.BaseLoginDialog.callbackSuccess(BaseLoginDialog.java:26)
																	at com.chsdk.moduel.login.AutoLoginDialog.loginSuccess(AutoLoginDialog.java:110)
																	at com.chsdk.moduel.login.request.BaseLoginRequest.onLoginSuccess(BaseLoginRequest.java:108)
																	at com.chsdk.moduel.login.request.BaseLoginRequest.handleLoginResult(BaseLoginRequest.java:95)
																	at com.chsdk.moduel.login.request.BaseLoginRequest.success(BaseLoginRequest.java:74)
																	at com.chsdk.moduel.login.request.BaseLoginRequest.success(BaseLoginRequest.java:23)
																	at com.chsdk.http.okhttp.BaseCallBack$1.run(BaseCallBack.java:81)
																	at android.os.Handler.handleCallback(Handler.java:873)
																	at android.os.Handler.dispatchMessage(Handler.java:99)
																	at android.os.Looper.loop(Looper.java:193)
																	at android.app.ActivityThread.main(ActivityThread.java:6825)
																	at java.lang.reflect.Method.invoke(Native Method)
																	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
																	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:860)
ActivityThread          com.yddm.haiwai.game                 W  handleWindowVisibility: no activity for token android.os.BinderProxy@2dea904
FA                      com.yddm.haiwai.game                 V  onActivityCreated
Cocos2dxActivity        com.yddm.haiwai.game                 D  model=V1824A
Cocos2dxActivity        com.yddm.haiwai.game                 D  product=V1824A
Cocos2dxActivity        com.yddm.haiwai.game                 D  isEmulator=false
EngineDataManager.cpp   com.yddm.haiwai.game                 D  nativeSetSupportOptimization: 0
FA                      com.yddm.haiwai.game                 V  Connecting to remote service
zch                     com.yddm.haiwai.game                 D  getAppID==========10100
zch                     com.yddm.haiwai.game                 D  MainActivity onStart
Cocos2dxActivity        com.yddm.haiwai.game                 D  onResume()
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  onBecameForeground
AppsFlyer_6.3.2         com.yddm.haiwai.game                 D  No deep link detected
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  Last Launch attempt: 2023/09/12 03:39:41.375 +0000;
																								Last successful Launch event: 2023/09/12 03:39:42.804 +0000;
																								Sending launch (+40573 ms)
FA                      com.yddm.haiwai.game                 V  Activity resumed, time: 6636560
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  sendWithEvent from activity: com.cqrmw.mwsdk.CHApplication
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  Trying to fetch GAID..
zch                     com.yddm.haiwai.game                 D  MainActivity onResume
CH_SDK                  com.yddm.haiwai.game                 D  CHSdk`onResume
CH_SDK                  com.yddm.haiwai.game                 D  *SdkLifeCycle`onResumeAction`com.chsdk.moduel.pay.PayManager$1
CH_SDK                  com.yddm.haiwai.game                 D  *PayPlatform`onResume
CH_SDK                  com.yddm.haiwai.game                 D  *GooglePlayExcutor`checkPurchaseConsumeState
CH_SDK                  com.yddm.haiwai.game                 D  *ShareManager`onResume
Finsky                  com.android.vending                  I  [392] knt.a(19): com.yddm.haiwai.game: Account from first account - [wVfsS5U8pcd2pVq_EIG48CenXLX7kwuHbTaGcBOATyc]
Finsky                  com.android.vending                  I  [392] knt.a(67): Billing preferred account via installer for com.yddm.haiwai.game: [wVfsS5U8pcd2pVq_EIG48CenXLX7kwuHbTaGcBOATyc]
CH_SDK                  com.yddm.haiwai.game                 D  *GooglePlayExcutor`onQueryPurchasesResponse`Response Code: OK, Debug Message: `0
CH_SDK                  com.yddm.haiwai.game                 D  *GooglePlayExcutor`checkPurchaseConsume no need
FA                      com.yddm.haiwai.game                 V  Connection attempt already in progress
FA                      com.yddm.haiwai.game                 V  Connection attempt already in progress
EGL_adreno              com.yddm.haiwai.game                 E  tid 22159: eglSurfaceAttrib(1338): error 0x3009 (EGL_BAD_MATCH)
OpenGLRenderer          com.yddm.haiwai.game                 W  Failed to set EGL_SWAP_BEHAVIOR on surface 0x7fff595ee380, error=EGL_BAD_MATCH
HostConnection          com.yddm.haiwai.game                 I  HostConnection::HostConnection: pid=22091, tid=22295, this=0x7fff5969f260
<no-tag>                com.yddm.haiwai.game                 I  fastpipe: Connect success
HostConnection          com.yddm.haiwai.game                 D  HostRPC::connect sucess: app=com.yddm.haiwai.game, pid=22091, tid=22295, this=0x7fff481efe40
HostConnection          com.yddm.haiwai.game                 D  queryAndSetGLESMaxVersion select gles-version: 3.1 hostGLVersion:46 process:com.yddm.haiwai.game
EGL_adreno              com.yddm.haiwai.game                 I  eglCreateContext request GLES major-version=2
EGL_adreno              com.yddm.haiwai.game                 D  eglCreateContext: 0x7fff5969d100: maj 3 min 1 rcv 4
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  ******* sendTrackingWithEvent: Launch
AppsFlyer_6.3.2         com.yddm.haiwai.game                 W  Exception while collecting facebook's attribution ID. 
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  IMEI was not collected.
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  Android ID was not collected.
EGL_adreno              com.yddm.haiwai.game                 D  eglMakeCurrent: 0x7fff68837a20: ver 3 1 (tinfo 0x7fff59c544c0)
AppsFlyerOaid6.2.4      com.yddm.haiwai.game                 I  Fetch 2 ms
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  AppsFlyer: first launch date: 2023-09-11_115844+0000
AppsFlyer_6.3.2         com.yddm.haiwai.game                 D  didConfigureTokenRefreshService=false
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  AppsFlyerLib.sendWithEvent
EGL_adreno              com.yddm.haiwai.game                 D  eglMakeCurrent: 0x7fff5969d100: ver 3 1 (tinfo 0x7fff727fdbe0)
FA                      com.yddm.haiwai.game                 D  Connected to remote service
FA                      com.yddm.haiwai.game                 V  Processing queued up service tasks: 3
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  url: https://launches.appsflyer.com/api/v6.3/androidevent?app_id=com.yddm.haiwai.game&buildnumber=6.3.2
cocos2d-x debug info    com.yddm.haiwai.game                 D  reload all texture
NotificationEntryMgr    com.android.systemui                 W  removeNotification for unknown key: 0|com.yddm.haiwai.game|0|FCM-Notification:6624366|10055
SurfaceFlinger          surfaceflinger                       W  Attempting to set client state on removed layer: Surface(name=AppWindowToken{e5dfebb token=Token{f85cf4a ActivityRecord{a055cb5 u0 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity t31}}})/@0x816baaa - animation-leash#0
SurfaceFlinger          surfaceflinger                       W  Attempting to destroy on removed layer: Surface(name=AppWindowToken{e5dfebb token=Token{f85cf4a ActivityRecord{a055cb5 u0 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity t31}}})/@0x816baaa - animation-leash#0
Cocos2dxActivity        com.yddm.haiwai.game                 D  onWindowFocusChanged() hasFocus=true
cocos2d-x debug info    com.yddm.haiwai.game                 D  Dirty Uniform and Attributes of GLProgramState
chatty                  com.yddm.haiwai.game                 I  uid=10055(com.yddm.haiwai.game) GLThread 498 identical 5 lines
cocos2d-x debug info    com.yddm.haiwai.game                 D  Dirty Uniform and Attributes of GLProgramState
AppsFlyer_6.3.2         com.yddm.haiwai.game                 I  response code: 200
AppsFlyer_6.3.2         com.yddm.haiwai.game                 D  [GCD-A01] Loading conversion data. Counter: 40
AppsFlyer_6.3.2         com.yddm.haiwai.game                 D  [GCD-A02] Calling onConversionDataSuccess with:
																								{install_time=2023-09-11 11:58:44.223, af_status=Organic, af_message=organic install, is_first_launch=false}
CH_SDK                  com.yddm.haiwai.game                 D  *AppsFlyer`onConversionDataSuccess`{install_time=2023-09-11 11:58:44.223, af_status=Organic, af_message=organic install, is_first_launch=false}
cocos2d-x debug info    com.yddm.haiwai.game                 D  Dirty Uniform and Attributes of GLProgramState
HostConnection          com.yddm.haiwai.game                 D  glGetError exceeded.
eglCodecCommon          com.yddm.haiwai.game                 E  removeVertexArrayObject: ERROR: cannot delete VAO 0!
chatty                  com.yddm.haiwai.game                 I  uid=10055(com.yddm.haiwai.game) GLThread 498 identical 2 lines
eglCodecCommon          com.yddm.haiwai.game                 E  removeVertexArrayObject: ERROR: cannot delete VAO 0!
system_server           system_process                       W  Failed to determine oat file name for dex location /data/app/com.yddm.haiwai.game-ZKTqcH16Y0TqYn-Fr7JM9w==/base.apk: Dalvik cache directory does not exist
ActivityManager         system_process                       I  Displayed com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity: +1s25ms
EngineDataManager.cpp   com.yddm.haiwai.game                 D  setAnimationInterval by engine: 0.0333
EngineDataManager.cpp   com.yddm.haiwai.game                 D  JNI setAnimationInterval: 0.033333
cocos2d-x debug info    com.yddm.haiwai.game                 D  [LUA-print] onEnterForeground
cocos2d-x debug info    com.yddm.haiwai.game                 D  [LUA-print] 发现新版本
cocos2d-x debug info    com.yddm.haiwai.game                 D  [LUA-print] ---new version found--> old:2.0.0.28, new:1.0.0.30
cocos2d-x debug info    com.yddm.haiwai.game                 D  [LUA-print] 本地版本高,不需要更新
GLESv2_enc              com.yddm.haiwai.game                 E  device/leidian/ldopengl/system/GLESv2_enc/GL2Encoder.cpp:s_glBindVertexArray:4499 GL error 0x502
SurfaceFlinger          surfaceflinger                       W  Attempting to set client state on removed layer: Splash Screen com.yddm.haiwai.game#0
SurfaceFlinger          surfaceflinger                       W  Attempting to destroy on removed layer: Splash Screen com.yddm.haiwai.game#0
libc                    com.yddm.haiwai.game                 A  Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 22295 (GLThread 498), pid 22091 (ddm.haiwai.game)
ActivityManager         system_process                       W    Force finishing activity com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity
InputDispatcher         system_process                       W  channel 'ba35995 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
---------------------------- PROCESS ENDED (22091) for package com.yddm.haiwai.game ----------------------------
InputDispatcher         system_process                       E  channel 'ba35995 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
ActivityManager         system_process                       I  Process com.yddm.haiwai.game (pid 22091) has died: vis  +99TOP 
WindowManager           system_process                       I  WIN DEATH: Window{ba35995 u0 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity}
InputDispatcher         system_process                       W  Attempted to unregister already unregistered input channel 'ba35995 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity (server)'
SurfaceFlinger          surfaceflinger                       W  Attempting to set client state on removed layer: com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity#0
SurfaceFlinger          surfaceflinger                       W  Attempting to destroy on removed layer: com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity#0
SurfaceFlinger          surfaceflinger                       W  Attempting to destroy on removed layer: AppWindowToken{e5dfebb token=Token{f85cf4a ActivityRecord{a055cb5 u0 com.yddm.haiwai.game/org.cocos2dx.lua.AppActivity t31}}}#0
CoreService             com.android.coreservice              I  notifyClosing notify tab closed taskPackageName:com.yddm.haiwai.game

先写一个通知栏,发现自己写的通知栏没有任何问题,都能正常唤起APP

C++裸包正常

将游戏的脚本代码换成了只有一个文件的main.lua

arduino 复制代码
log("ok")

并没有发生崩溃,说明游戏裸包是没有任何问题

lua框架

尝试仅加载游戏框架,屏幕没有任何渲染,发现也没有崩溃和异常,说明lua framework也没有问题

lua 复制代码
log("hello game lua")
require "config"
require "cocos.init"
log("ok")

渲染Sprite时也发生了崩溃

css 复制代码
require "config"
require "cocos.init"
local scene = cc.Scene:create()
local director = cc.Director:getInstance()
director:runWithScene(scene)

local root = cc.Node:create()
root:setName("root")
scene:addChild(root)

local size = cc.Director:getInstance():getWinSize()

local spr = cc.Sprite:create("res/1.png");
spr:setPosition(cc.p(size.width / 2, size.height / 2))
root:addChild(spr)

渲染label时,发生了崩溃

lua 复制代码
require "config"
require "cocos.init"
local scene = cc.Scene:create()
local director = cc.Director:getInstance()
director:runWithScene(scene)

local root = cc.Node:create()
root:setName("root")
scene:addChild(root)

local size = cc.Director:getInstance():getWinSize()
local label = cc.Label:create();
label:setSystemFontSize(150)
label:setString("ABC")
label:setPosition(cc.p(size.width / 2, size.height / 2))
root:addChild(label)

问题定位到了,是AppActivity的Create执行了2次导致的,当App在后台时,如果点击通知栏唤起APP,会重新执行AppActivity的OnCreate()

能想到的就是自己处理firebase的消息,如下:

java 复制代码
// 在处理Firebase通知栏消息时,创建Intent对象
Intent intent = new Intent(this, YourActivity.class); // YourActivity是您要启动的Activity
intent.putExtra("fromNotification", true); // 添加一个标志,表示是Firebase通知栏消息启动的

// 启动Activity
startActivity(intent);

在AppActivity里面

java 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    boolean fromNotification = getIntent().getBooleanExtra("fromNotification", false);
    if (fromNotification) {
        // 这是从Firebase通知栏消息打开的应用程序
        // 在这里处理相应的逻辑
    } else {
        // 这不是从Firebase通知栏消息打开的应用程序
        // 在这里执行其他代码
    }
}

但是感觉这样有点麻烦,继续排查,我们可以尝试着将intent的透传参数打印出来

java 复制代码
Intent intent = getIntent();
if (intent!=null){
    Bundle extra = intent.getExtras();
    if (extra != null){
        for(String key: extra.keySet()){
            Object value= extra.get(key);
            Log.d("intent extra","key:"+key+", value:"+value.toString());
        }
    }
}

firebase传递过来的参数有:

less 复制代码
key:google.delivered_priority, value:normal
key:google.sent_time,          value:1694586997451
key:google.ttl,                value:300
key:google.original_priority,  value:normal
key:from,                      value:185043606008
key:google.message_id,         value:0:1694586997458180%bab4c2e4bab4c2e4
key:gcm.n.analytics_data,      value:Bundle[mParcelledData.dataSize=100]
key:collapse_key,              value:com.yddm.haiwai.game

所以我们可以考虑给AppActivity里面加上intent拦截,发现仍旧报错,猜测可能是因为父类重复初始化导致的,后来尝试在Cocos2dActivity的onCreate里面拦截intent,也会报错

java 复制代码
private void resumeIfHasFocus() {
    if(hasFocus) {
        this.hideVirtualButton();
       Cocos2dxHelper.onResume();
       mGLSurfaceView.onResume();// null
    }
}
//java.lang.NullPointerException: Attempt to invoke virtual method 'void org.cocos2dx.lib.Cocos2dxGLSurfaceView.onResume()' on a null object reference

可能是Intent的Flag导致的

  • 正常启动的flag: 268435456 FLAG_ACTIVITY_NEW_TASK
  • firebase过来的: 339738624 FLAG_ACTIVITY_BROUGHT_TO_FRONT

正常情况下,Cocos2dActivity.mGLSurfaceView是不能发现变化的。

当出现问题时,发现Cocos2dActivity.mGLSurfaceView实例发生了变化,why?

FLAG_ACTIVITY_BROUGHT_TO_FRONT

Android 中的一个标志(flag),用于控制活动(Activity)在启动时的行为。该标志用于指示要启动的活动是否应该移动到前台,而不是创建新的实例。

具体来说,当使用 startActivity() 方法启动一个活动时,可以使用 FLAG_ACTIVITY_BROUGHT_TO_FRONT 标志来修改启动行为。如果目标活动已经存在于任务堆栈中,设置了该标志的启动将会将该活动移动到前台,而不是创建新的活动实例。如果目标活动不存在,则会创建新的活动实例。

很明显目标活动不存在,重新创建了,接入firebase后,app在后台,为啥FLAG_ACTIVITY_BROUGHT_TO_FRONT会导致重新创建一个Activity呢?

后来发现这个FLAG_ACTIVITY_BROUGHT_TO_FRONT问题不大,我自己的也这么设置没有问题,尝试修改了下我的nofity,最后也稳定复现了:

ini 复制代码
Intent intent = new Intent(context, AppActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER); // 加上这个就不会重复穿件Activity

打印flag标志的代码:

java 复制代码
private void checkFlag(int flags){
    for (int i = 0; i < 32; i++) {
        int flag = 1 << i;

        if ((flags & flag) != 0) {
            printIntentFlag(flag);
        }
    }
}

public static void printIntentFlag(int flag) {
    String bin = Integer.toBinaryString(flag);
    Map<Integer,String> sysFlags=new HashMap<>();
    sysFlags.put(Intent.FLAG_ACTIVITY_NEW_TASK,"FLAG_ACTIVITY_NEW_TASK");
    sysFlags.put(Intent.FLAG_ACTIVITY_CLEAR_TOP,"FLAG_ACTIVITY_CLEAR_TOP");
    sysFlags.put(Intent.FLAG_ACTIVITY_SINGLE_TOP,"FLAG_ACTIVITY_SINGLE_TOP");
    sysFlags.put(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT,"FLAG_ACTIVITY_BROUGHT_TO_FRONT");
    sysFlags.put(Intent.FLAG_RECEIVER_REGISTERED_ONLY,"FLAG_RECEIVER_REGISTERED_ONLY");

    String name= sysFlags.get(flag);
    if(name!=null){
        Log.d("intent flag", name);
    }
}

解决办法

firebase生成的通知栏消息,点击时会根据一定条件重新创建一个Activity,内部实现机制不太了解,但是要修复这个问题只需要它不重复创建Activity即可。

无意中,ChatGPT给出了一个答案,可以修改启动模式,这么做也有弊端,就是无法再收到intent透传的参数,所以终极解决方案还是得自己处理firebase的message

xml 复制代码
<activity android:name=".YourActivity"
          android:launchMode="singleInstance">
</activity>
  • SingleTask 启动模式:当启动一个拥有 singleTask 启动模式的 Activity 时,系统会检查是否已经存在具有相同任务栈的实例。如果存在,则该实例将被调出前台并接收新的 Intent,而不会创建新的实例。如果不存在具有相同任务栈的实例,则会创建新的实例并将其置于新的任务栈中。
  • SingleInstance 启动模式:这是一种特殊的 singleTask 模式,它会为目标 Activity 创建一个单独的任务栈,并且该任务栈只包含该 Activity 的实例。当启动一个拥有 singleInstance 启动模式的 Activity 时,系统会为其创建一个新的任务栈,并将该 Activity 放置在新的任务栈中。无论后续的 Intent 如何,都不会在同一个任务栈中创建其他 Activity 的实例。
相关推荐
狂奔solar几秒前
分享个好玩的,在k8s上部署web版macos
前端·macos·kubernetes
qiyi.sky3 分钟前
JavaWeb——Web入门(8/9)- Tomcat:基本使用(下载与安装、目录结构介绍、启动与关闭、可能出现的问题及解决方案、总结)
java·前端·笔记·学习·tomcat
清云随笔24 分钟前
axios 实现 无感刷新方案
前端
鑫宝Code26 分钟前
【React】状态管理之Redux
前端·react.js·前端框架
忠实米线34 分钟前
使用pdf-lib.js实现pdf添加自定义水印功能
前端·javascript·pdf
pink大呲花36 分钟前
关于番外篇-CSS3新增特性
前端·css·css3
少年维持着烦恼.40 分钟前
第八章习题
前端·css·html
我是哈哈hh43 分钟前
HTML5和CSS3的进阶_HTML5和CSS3的新增特性
开发语言·前端·css·html·css3·html5·web
田本初1 小时前
如何修改npm包
前端·npm·node.js