1. 程式人生 > >關於emjoy表情在android5.x以上系統觸發jni錯誤的修改(基於cocos2dx2.1.5修改)

關於emjoy表情在android5.x以上系統觸發jni錯誤的修改(基於cocos2dx2.1.5修改)

一直糾結著這個錯誤,後來看別人的文章找到靈感,於是完善了基於cocos2dx2.1.5修改的大笑


具體報錯:JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0xed

解決辦法(基於coocs2dx2.1.5):

在CCImage.cpp裡面的getBitmapFromJavaShadowStroke方法中,emjoy表情在jstring jstrText = methodInfo.env->NewStringUTF(text);

的時候觸發崩潰,原因大致估計是因為emjoy不能被utf識別,於是繞過NewStringUTF,將之轉化為byte[]來繞過.具體遮蔽jstring jstrText = methodInfo.env->NewStringUTF(text);修改為

 bool getBitmapFromJavaShadowStroke(	const char *text,
    									int nWidth,
    									int nHeight,
    									CCImage::ETextAlign eAlignMask,
    									const char * pFontName,
    									float fontSize,
    									float textTintR 		= 1.0,
    									float textTintG 		= 1.0,
    									float textTintB 		= 1.0,
    									bool shadow 			= false,
    									float shadowDeltaX 		= 0.0,
    									float shadowDeltaY 		= 0.0,
    									float shadowBlur 		= 0.0,
    									float shadowIntensity 	= 0.0,
    									bool stroke 			= false,
    									float strokeColorR 		= 0.0,
    									float strokeColorG 		= 0.0,
    									float strokeColorB 		= 0.0,
    									float strokeSize 		= 0.0 )
    {
           JniMethodInfo methodInfo;
           if (! JniHelper::getStaticMethodInfo(methodInfo, "org/cocos2dx/lib/Cocos2dxBitmap", "createTextBitmapShadowStroke",
               "([BLjava/lang/String;IFFFIIIZFFFZFFFF)V"))
           {
               CCLOG("%s %d: error to get methodInfo", __FILE__, __LINE__);
               return false;
           }
        
        
        
           // Do a full lookup for the font path using CCFileUtils in case the given font name is a relative path to a font file asset,
           // or the path has been mapped to a different location in the app package:
           std::string fullPathOrFontName = CCFileUtils::sharedFileUtils()->fullPathForFilename(pFontName);
        
		   // If the path name returned includes the 'assets' dir then that needs to be removed, because the android.content.Context
		   // requires this portion of the path to be omitted for assets inside the app package.
		   if (fullPathOrFontName.find("assets/") == 0)
		   {
               fullPathOrFontName = fullPathOrFontName.substr(strlen("assets/"));	// Chop out the 'assets/' portion of the path.
           }

           /**create bitmap
            * this method call Cococs2dx.createBitmap()(java code) to create the bitmap, the java code
            * will call Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC() to init the width, height
            * and data.
            * use this approach to decrease the jni call number
           */
           //jstring jstrText = methodInfo.env->NewStringUTF(text);

		   /**
		    * 修復emioy表情在android5.x以上系統jni崩潰bug
		    * 將string修改為byte[].繞過jni在android5.x以上系統出現emjoy崩潰問題
		    */
		   int strLen = strlen(text);
		   jbyteArray byteArray = methodInfo.env->NewByteArray(strLen);
		   methodInfo.env->SetByteArrayRegion(byteArray, 0, strLen, reinterpret_cast<const jbyte*>(text));
           jstring jstrFont = methodInfo.env->NewStringUTF(fullPathOrFontName.c_str());

           methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, byteArray,
               jstrFont, (int)fontSize, textTintR, textTintG, textTintB, eAlignMask, nWidth, nHeight, shadow, shadowDeltaX, -shadowDeltaY, shadowBlur, stroke, strokeColorR, strokeColorG, strokeColorB, strokeSize);

           methodInfo.env->DeleteLocalRef(byteArray);
           methodInfo.env->DeleteLocalRef(jstrFont);
           methodInfo.env->DeleteLocalRef(methodInfo.classID);

           return true;
    }

同時java對應修改傳入引數

Cocos2dxBitmap.java中,createTextBitmapShadowStroke傳入引數修改為byte[]型別,然後將byte[]轉化為string來正常直接emjoy的輸出

public static void createTextBitmapShadowStroke(byte[] pString_byte,
		final String pFontName,final int pFontSize,final float fontTintR,
		final float fontTintG,final float fontTintB,final int pAlignment,
		final int pWidth,final int pHeight,final boolean shadow,
		final float shadowDX,final float shadowDY,final float shadowBlur,
		final boolean stroke,final float strokeR,final float strokeG,
		final float strokeB,final float strokeSize) throws UnsupportedEncodingException
	{
		/**
		 * 將string修改為byte[].繞過jni在android5.x以上系統出現emjoy崩潰問題,然後重新轉化為string來繼續輸出emjoy表情
		 * @author lfy
		 */
		String pString=new String(pString_byte,"UTF-8");
		
		final int horizontalAlignment=pAlignment&0x0F;
		final int verticalAlignment=(pAlignment>>4)&0x0F;

		try
		{
			pString=Cocos2dxBitmap.refactorString(pString);
		}
		catch(java.lang.Exception e)
		{

		}
		final Paint paint=Cocos2dxBitmap.newPaint(pFontName,pFontSize,
			horizontalAlignment);

		// set the paint color
		paint.setARGB(255,(int)(255.0*fontTintR),(int)(255.0*fontTintG),
			(int)(255.0*fontTintB));

		// modify some char error... s cdy20140731
		// final TextProperty
		// textProperty=Cocos2dxBitmap.computeTextProperty(
		// pString,pWidth,pHeight,paint);
		// final int bitmapTotalHeight=(pHeight==0?textProperty.mTotalHeight
		// :pHeight);
		TextProperty textProperty=null;
		int bitmapTotalHeight=0;
		textProperty=Cocos2dxBitmap.computeTextProperty(pString,pWidth,
			pHeight,paint);
		bitmapTotalHeight=(pHeight==0?textProperty.mTotalHeight:pHeight);

		if(bitmapTotalHeight<=0||textProperty.mMaxWidth<=0)
		{
			textProperty=Cocos2dxBitmap.computeTextProperty(" ",pWidth,
				pHeight,paint);
			bitmapTotalHeight=(pHeight==0?textProperty.mTotalHeight:pHeight);
		}
		// modify some char error... e

		// padding needed when using shadows (not used otherwise)
		float bitmapPaddingX=0.0f;
		float bitmapPaddingY=0.0f;
		float renderTextDeltaX=0.0f;
		float renderTextDeltaY=0.0f;

		if(shadow)
		{

			int shadowColor=0xff7d7d7d;
			paint.setShadowLayer(shadowBlur,shadowDX,shadowDY,shadowColor);

			bitmapPaddingX=Math.abs(shadowDX);
			bitmapPaddingY=Math.abs(shadowDY);

			if(shadowDX<0.0)
			{
				renderTextDeltaX=bitmapPaddingX;
			}

			if(shadowDY<0.0)
			{
				renderTextDeltaY=bitmapPaddingY;
			}
		}

		final Bitmap bitmap=Bitmap.createBitmap(textProperty.mMaxWidth
			+(int)bitmapPaddingX,bitmapTotalHeight+(int)bitmapPaddingY,
			Bitmap.Config.ARGB_8888);

		final Canvas canvas=new Canvas(bitmap);

		/* Draw string. */
		final FontMetricsInt fontMetricsInt=paint.getFontMetricsInt();

		int x=0;
		int y=Cocos2dxBitmap.computeY(fontMetricsInt,pHeight,
			textProperty.mTotalHeight,verticalAlignment);

		final String[] lines=textProperty.mLines;

		for(final String line:lines)
		{

			x=Cocos2dxBitmap.computeX(line,textProperty.mMaxWidth,
				horizontalAlignment);
			canvas
				.drawText(line,x+renderTextDeltaX,y+renderTextDeltaY,paint);
			y+=textProperty.mHeightPerLine;

		}

		// draw again with stroke on if needed
		if(stroke)
		{

			final Paint paintStroke=Cocos2dxBitmap.newPaint(pFontName,
				pFontSize,horizontalAlignment);
			paintStroke.setStyle(Paint.Style.STROKE);
			paintStroke.setStrokeWidth(strokeSize*0.5f);
			paintStroke.setARGB(255,(int)strokeR*255,(int)strokeG*255,
				(int)strokeB*255);

			x=0;
			y=Cocos2dxBitmap.computeY(fontMetricsInt,pHeight,
				textProperty.mTotalHeight,verticalAlignment);
			final String[] lines2=textProperty.mLines;

			for(final String line:lines2)
			{

				x=Cocos2dxBitmap.computeX(line,textProperty.mMaxWidth,
					horizontalAlignment);
				canvas.drawText(line,x+renderTextDeltaX,y+renderTextDeltaY,
					paintStroke);
				y+=textProperty.mHeightPerLine;

			}

		}

		Cocos2dxBitmap.initNativeObject(bitmap);
	}

如此可以正常在聊天中輸入emjoy表情了,如果有什麼差錯,麻煩指正下,個人QQ1908662823