制作包含UI控件的jar
前段时间需要给非己平台上的APP(我们做机顶盒,但有些直播软件会装到别人的盒子中)升级,非得弄一个jar为负责升级功能。
这本不难,但是需求中说jar只需要一个packageName,便能实现升级,所有弹框及提示均集成到jar中。
大家都知道jar并不能连res也导出去,这可能是谷歌为防止R.id重复,R类打包之后失效,实际是因为R类的内部类里面的属性失效,因
为打包之后这些属性的值就固定了,但是实际项目中这些值是在编译时有系统自动分配的,无法在编译前固定。但好像也有人这样做:
如果能在view初始化(及程序运行时),执行一个初始化过程,
将此时项目中R内部类的对应值,复制给view jar包中的R内部类的对
应值,则能解决这个问题。由于各个View jar包中的R类内部类的属
性个数和属性名是不确定的,所以使用java反射机制来实现上述思路
明显太麻烦了。
我需要实现的是:制作一个jar , 包含指定样式的提示UI(一个Dialog) , 能实现升级功能 。
通过搜索可知道,实现这种需求有两个办法:
1.通过一个中介工程A, 把A为Library,引入jar, 然后你的工作工程B,再引入A。网上说的较多的方法,但对我为来有局限性。
2.因为我们的编译器在引入jar时,会自动把assets中的内容合并到工程中的assets目录中。所以,我们可以通过把资源图片放到assets目录,并在代码中读取图片,来构建布局。
1 //-读取asset中的图片 2 private void setBackgroundDrawable(ImageButton bt , String name){ 3 try { 4 AssetManager localAssetManager = context.getAssets(); 5 InputStream localInputStream = localAssetManager.open(name); 6 Bitmap localBitmap = BitmapFactory.decodeStream(localInputStream); 7 localInputStream.close(); 8 Drawable drawable = new BitmapDrawable(localBitmap); 9 if(drawable!=null){ 10 bt.setImageDrawable(drawable); 11 } 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } 15 } 16 17 18 -制作一个dialog的layout 19 /** 框体 */ 20 private LinearLayout getLinearLayout(){ 21 LinearLayout layout = new LinearLayout(context); 22 layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); 23 layout.setOrientation(LinearLayout.VERTICAL); 24 layout.setBackgroundDrawable(getDrawable("upgrade_dialog_1.png")); 25 26 27 TextView textView = new TextView(context); 28 if(title!=null){ 29 textView.setText(title); 30 }else{ 31 textView.setText("发现新版本,是否升级?"); 32 } 33 textView.setTextSize(24); 34 textView.setTextColor(Color.WHITE); 35 textView.setPadding(0, 80, 0, 0); 36 textView.setGravity(Gravity.CENTER_HORIZONTAL); 37 38 layout.addView(textView); 39 layout.addView(getButtonLinearLayout()); 40 41 return layout; 42 } 43 44 /** 按钮部分 */ 45 private LinearLayout getButtonLinearLayout(){ 46 LinearLayout layout = new LinearLayout(context); 47 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(600, 40); 48 layoutParams.topMargin = 55; 49 layout.setLayoutParams(layoutParams); 50 layout.setOrientation(LinearLayout.HORIZONTAL); 51 layout.setGravity(Gravity.CENTER_HORIZONTAL); 52 53 ImageButton yes = new ImageButton(context); 54 yes.setLayoutParams(new LayoutParams(150, 34)); 55 setBackgroundDrawable(yes, "yes.png"); 56 yes.setId(777771);//也可通过setTag为查找对应的控件 57 58 TextView tv = new TextView(context); 59 tv.setLayoutParams(new LayoutParams(20, 1)); 60 61 ImageButton no = new ImageButton(context); 62 no.setLayoutParams(new LayoutParams(150, 34)); 63 setBackgroundDrawable(no, "no.png"); 64 no.setId(777772); 65 66 layout.addView(yes); 67 layout.addView(tv); 68 layout.addView(no); 69 70 return layout; 71 } 72 73 //-制作一个dialog 74 public UpgradDialog creatDialog(){ 75 LinearLayout layout = getLinearLayout(); 76 final UpgradDialog dialog = new UpgradDialog(context,android.R.style.Theme_Translucent_NoTitleBar_Fullscreen); 77 final ImageButton yes = (ImageButton) layout.findViewById(777771); 78 final ImageButton no = (ImageButton) layout.findViewById(777772); 79 80 yes.setOnFocusChangeListener(new View.OnFocusChangeListener() { 81 public void onFocusChange(View arg0, boolean tag) { 82 if(tag){ 83 setBackgroundDrawable(yes, "yes_focus.png"); 84 }else{ 85 setBackgroundDrawable(yes, "yes.png"); 86 } 87 } 88 }); 89 yes.setOnClickListener(new View.OnClickListener() { 90 public void onClick(View arg0) { 91 setBackgroundDrawable(yes, "yes_click.png"); 92 yes.postDelayed(new Runnable() { 93 public void run() { 94 setBackgroundDrawable(yes, "yes_focus.png"); 95 if(null!=positiveClickListener){ 96 positiveClickListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); 97 } 98 } 99 }, 400); 100 } 101 }); 102 103 no.setOnFocusChangeListener(new View.OnFocusChangeListener() { 104 public void onFocusChange(View arg0, boolean tag) { 105 if(tag){ 106 setBackgroundDrawable(no, "no_focus.png"); 107 }else{ 108 setBackgroundDrawable(no, "no.png"); 109 } 110 } 111 }); 112 no.setOnClickListener(new View.OnClickListener() { 113 public void onClick(View arg0) { 114 setBackgroundDrawable(no, "no_click.png"); 115 no.postDelayed(new Runnable() { 116 public void run() { 117 setBackgroundDrawable(no, "no_focus.png"); 118 if(null!=negativeClickListener){ 119 negativeClickListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); 120 } 121 } 122 }, 400); 123 } 124 }); 125 126 yes.setFocusable(true); 127 yes.setClickable(true); 128 129 no.setFocusable(true); 130 no.setClickable(true); 131 132 Window window = dialog.getWindow(); 133 WindowManager.LayoutParams lp = window.getAttributes(); 134 lp.alpha = 0.9f; 135 lp.width = 600; 136 lp.height = 230; 137 window.setAttributes(lp); 138 139 yes.requestFocus(); 140 141 dialog.setContentView(layout); 142 return dialog; 143 } 144
以上就是一个通过读取assets中的图片来构建一个dialog的代码例子,需要注意的是:
1.jar中assets的图片命名需要有一定标识性,尽量命名的独特一点,不能与使用他的项目中assets的图片重名;
2.升级进度条所使用的prgressbar,需要用反射为设置成条状
progressBar = new ProgressBar(context); ProgressBarUtils.setFieldValue(progressBar, "mOnlyIndeterminate", new Boolean(false));//关键 progressBar.setIndeterminate(false); progressBar.setProgressDrawable(context.getResources().getDrawable(android.R.drawable.progress_horizontal));//) progressBar.setIndeterminateDrawable(context.getResources().getDrawable(android.R.drawable.progress_indeterminate_horizontal)); progressBar.setMinimumHeight(6); progressBar.setProgress(10); /*---------------------给出一个工具类:----------------------------*/ public class ProgressBarUtils { private ProgressBarUtils() { } /** * 直接设置对象属性值,无视private/protected修饰符,不经过setter函数. */ public static void setFieldValue(final Object object, final String fieldName, final Object value) { Field field = getDeclaredField(object, fieldName); if (field == null) throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]"); makeAccessible(field); try { field.set(object, value); } catch (IllegalAccessException e) { Log.e("zbkc", "", e); } } /** * 循环向上转型,获取对象的DeclaredField. */ protected static Field getDeclaredField(final Object object, final String fieldName) { return getDeclaredField(object.getClass(), fieldName); } /** * 循环向上转型,获取类的DeclaredField. */ @SuppressWarnings("unchecked") protected static Field getDeclaredField(final Class clazz, final String fieldName) { for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) { try { return superClass.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { // Field不在当前类定义,继续向上转型 } } return null; } /** * 强制转换fileld可访问. */ protected static void makeAccessible(Field field) { if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) { field.setAccessible(true); } } } /*----------------------------------------------*/
如果是windows开发的话,这结束了。。。。 如果是linux的话,还不行。
1. 因为linux下,编译APP,还需要在mk文件中指定所使用jar包。
/```````````````````````/
LOCAL_STATIC_JAVA_LIBRARIES := upgrade //(upgrade为自定义名称)
/```````````````````````/
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := upgrade:libs/upgrade_service.jar //(自定义名称+: +jar在工程中的路径)
2.源码下编译APP,不会像编译器那样,自动把jar中的assets合并到工程目录中的assets,需要手动把他们合并。
----------------------------这是我写的第一篇,写的很乱,如果有人搜到,看到,少走点弯路也是极好的。。。。。。。。