ButterKnife dump script

background

Although ButterKnife helps us to save the tedious findViewById(), it is very fast and convenient to use, but it has advantages and disadvantages. During compilation, ButterKnife will generate additional class files, which contributes a lot to the increase of the number of methods of App, and it is inconvenient to use ButterKnife in library module, so it is imperative to optimize the project and discard ButterKnife.

Script description

(1) parse @ bind view annotation to get view id, and generate findViewById at the call of ButterKnife.bind to achieve the replacement effect.
(2) it supports specifying directory parameters, traversing directories, and recursive replacement. After the script runs, you need to manually clear the imports.
(3) replacing @ OnClick annotation is not supported temporarily.
(4) console output file completion status.

Example

sky:~ sky$ python replace_butterknife.py DiscountStartShowController.java

Script code

#!/usr/bin/env python
# by sky
 
import os, sys, re
 
butter_knife_egx = re.compile('.*@BindView\(R[2]?.id.(.*)\)')
view_define_egx = re.compile('\s*(.*)\s+(.*);')
butter_bind_egx = re.compile('\s*ButterKnife.bind\([^,]+[,]?\s*(.*)\);')
 
def convert(file):
  butterknifeline = False
  view_id = None
  list = file.readlines()
  new_list = []
  findview_lines = []
 
  for index in range(len(list)):
    line = list[index]
    if butterknifeline:
      result = view_define_egx.match(line)
      if result:
 
        # private TextView tvTitle
        view_define_line = '\t' + 'private ' + result.group(1) + ' ' + result.group(2) + ';\n'
 
        # tvTitle = findViewById(R.id.tv_title)
        new_line = '\t' + result.group(2) + ' = '
        if result.group(1) != 'View':
          new_line += '(' + result.group(1) + ')'
 
        new_line += 'findViewById(R.id.' + view_id +');\n'
 
        findview_lines.append(new_line)
        new_list.append(view_define_line)
        butterknifeline = False
      else:
        new_list.append(line)
    else:
      m = butter_knife_egx.match(line)
      if m:
        view_id = m.group(1)
        butterknifeline = True
      elif len(findview_lines) > 0:
        m = butter_bind_egx.match(line)
        if m:
          parent_view = m.group(1)
          create_findviewbyid(new_list, findview_lines, parent_view)
          findview_lines = []
        else:
          new_list.append(line)
      else:
        new_list.append(line)
 
  file.seek(0)
  file.writelines(new_list)
 
 
# tvTitle = view.findViewById(R.id.tv_title)
def create_findviewbyid(new_list, findview_lines, parent_view):
  for line in findview_lines:
    if parent_view:
      line = line.replace('findViewById', parent_view + '.findViewById')
    new_list.append(line)
 
 
# recurse replace butter knife
def convert_recurse(path_name):
  if os.path.isfile(path_name):
    if not path_name.endswith('.java'):
      return
    with open(path_name, 'r+') as f:
      convert(f)
      print path_name + ' is done'
  elif os.path.isdir(path_name):
    for file_name in os.listdir(path_name):
      convert_recurse(path_name + '/' + file_name)
  else:
    print path_name + ' is invalid'
 
 
if __name__ == "__main__":
 
  if len(sys.argv) < 2:
    print 'args error'
    quit()
 
  path_name = sys.argv[1]
  convert_recurse(path_name)

Tags: Mobile ButterKnife Python Java

Posted on Sun, 08 Dec 2019 17:19:33 -0800 by sungpeng