Programmatically adding argument to view that already uses a context filter
I now have a better understanding and found a solution. hook_views_pre_view() is indeed too early to see arguments that are NOT passed to the view via URL. That explains why $view->args was empty in my case. In hook_views_post_build() you do see ALL arguments (URL+nonURL) passed to the view. However, the way I solved my issue is still using   $args[0] = $value; in hook_views_pre_view. That means the first argument passed to all views will always be $value. For views that are using additional arguments, Drupal will add them to $args later on. In my special case I have views that might not necessarily need the first argument that I pass, so I had to add a contextual filter Global: Null (at the first position) that allows a contextual filter value to be ignored (and as a default I set 0). This way each view does have the correct number of contextual filters and the order is correct, whether the view needs to use the very first argument or not. It might not seem intuituve to pass an argument to every view, even though not all views really need it, but adding a Global: Null dummy filter is easier than excluding views in an if() statement and always having to modify the module code when a new view has to be added later on.